DIT DOTS KO6ETZ HAM RADIO • ELECTRONICS • SOFTWARE 14.074 MHz TX PWR RX

ShackLink Mobile Client

Cross-Platform App – ShackLink

Full radio control on iOS and Android — built with .NET MAUI. Operate your shack from anywhere: on the home Wi-Fi the app auto-detects the server and uses the lowest-latency LAN path; off-network, type your tunnel URL and the app switches to the auth-gated unified WebSocket. Same UI, same features, every platform.

Android iOS

💡 Key Features

🌐

Operate From Anywhere

Auto-detect picks the LAN multi-port path at home; manual hostname switches to the unified-WebSocket transport for remote access through Cloudflare Tunnel, Tailscale Funnel, nginx, or a port-forward. HMAC-SHA-256 secret stored in platform secure storage (Keychain on iOS, EncryptedSharedPreferences on Android).

🔌

Frequency & Mode Control

Large LCD-style display, segment-tap up / down buttons, manual keyboard entry, rotary VFO knob overlay. Modes: LSB, USB, CW-L, CW-U, AM, FM, DIG-L, DIG-U with per-band smart step sizes.

📡

Multi-Rig Support

Switch between up to 4 OmniRig rigs with custom names. VFO A/B, Split, RIT, XIT all bidirectional with the radio.

🎧

Dual Audio Streams

Low-latency 12 kHz PCM (~150 ms) for live tuning + 192 kbps stereo HiFi MP3 for SSB / AM listening on cellular. Platform-native decode (Android MediaCodec, iOS AVPlayer). Mutually exclusive; auto-switches to 12 kHz on TX.

🔢

Eight Digital Decoders

CW (40+ WPM), RTTY (auto-detect baud + shift, two demod algorithms with picker), PSK31 (9 BPSK / QPSK variants with AFC and FEC), FT8 / FT4 (color-coded by SNR), SSTV (19 modes with image canvas + waterfall), WEFAX (weather-fax decoder), NAVTEX (SITOR-B maritime safety), and APRS (AX.25 packet radio).

🔊

Transmit Support

Chat-style timeline of incoming + outgoing. Voice (tap-to-toggle PTT), CW, RTTY, PSK31, APRS. Server enforces a single-owner lock; rejected sends are visually greyed.

📈

SDR Panadapter

Live scope + scrolling waterfall (SkiaSharp). Multi-SDR slot picker and Audio button when multiple devices are active. Tap-to-tune, drag-pan with comfort zone, RF / IF mode, FFT size picker (4K–32K). Same wire format as the desktop, server, and HA cards.

🎶

Audio Visualization

4 modes (Waterfall + spectrum overlay, Spectrum bars, Spectrum LED, Oscilloscope) with 6 themes, peak-hold colors, gain / contrast / range sliders. Same math as the desktop client — visual parity guaranteed.

💾

Memory Bank

90 local slots paginated 10×9 (long-press to save, tap to recall). Per-band band navigation across HF / VHF / UHF amateur and broadcast allocations.

🎤

Audio Recording

Save audio sessions locally with frequency / mode / timestamp filenames.

🔒

Auto-Reconnect

Resumes streaming, decoder subscriptions, and TX state on network blips. Auth state recovered from secure storage so you don’t re-prompt every reconnect.

SDR 3D waterfall panadapter

The SDR panadapter’s 3D waterfall — the live spectrum rendered as a rotatable, GPU-accelerated perspective terrain

📋 System Requirements

PlatformMinimum VersionNotes
AndroidAndroid 8.0 (API 26)Most phones from 2017 onwards
iOSiOS 14.0iPhone 6s+, iPad 5th gen+
Network (LAN)Wi-Fi or VPNApp auto-detects servers via UDP broadcast on port 8081 (broadcast includes name=<hostname>). Discovered servers appear in a Picker dropdown as HOSTNAME (IP). Connects on TCP 8080/8081/8082/8085 (legacy multi-port path).
Network (Remote)Wi-Fi, cellular, anywhereManually enter the server’s hostname or tunnel URL — app switches to the unified-WebSocket transport on port 8084 with HMAC auth. One port-forward / Cloudflare Tunnel / Tailscale Funnel covers everything.

🎮 User Interface

Connection Section

  • Server picker – A dropdown (Picker) that automatically lists all discovered ShackLink servers on the LAN as HOSTNAME (IP). Selecting a server fills the IP and port fields. When multiple servers are running, all appear simultaneously. Servers that stop broadcasting disappear after 12 seconds.
  • IP / hostname – LAN IP (e.g. 192.168.1.100) for the legacy multi-port path, or a hostname / tunnel URL (e.g. shacklink.example.com) to switch to the unified-WebSocket transport for remote access. Auto-filled when you pick a server from the dropdown.
  • Port8080 for the legacy LAN path (auto-set on UDP discovery), 8084 for the unified-WebSocket remote path (auto-set when you type a hostname).
  • Auth secret – For the unified-WebSocket path, the app prompts for the HMAC-SHA-256 hex secret from the server’s Tools → Security panel. Stored in platform secure storage (Keychain on iOS, EncryptedSharedPreferences on Android).
  • Connect Button – Tap to establish or close connection
  • Status Indicator – Shows Connected/Disconnected state

Two Transports, One Protocol

The app automatically picks one of two transports based on how it found the server:

  • LAN auto-detect → legacy multi-port — server’s UDP broadcast (including name=<hostname>) reached the device. Discovered servers appear in the server Picker dropdown as HOSTNAME (IP). App connects on TCP 8080/8081/8082/8085. Lowest-latency path; preserved indefinitely for home use.
  • Manual hostname → unified WebSocket — you typed an address that didn’t come from UDP discovery (typical for remote access through Cloudflare Tunnel, Tailscale Funnel, etc.). App opens a single wss://host:8084/ws with HMAC auth.

Either way, the radio control protocol is identical — the app’s view models don’t know which transport is in effect.

Frequency Display

The frequency is displayed in a split format for easy reading:

  • MHz – Megahertz (e.g., 14)
  • KHz – Kilohertz (e.g., 074)
  • Hz – Hertz (e.g., 000)

Each section has up/down arrow buttons for adjustment. The step size varies by mode.

Frequency dial and main screen
The split frequency display with per-digit up / down and the rotary VFO knob overlay

Mode Selection

Tap any mode button to change the operating mode. The selected mode is highlighted.

AM
FM
SW
MW
LW
LSB
USB
CW

🌐 Band Selection

Pre-configured bands with frequency limits:

BandFrequency RangeDescription
LW148.5 – 283.5 kHzLong Wave broadcast
MW530 – 1700 kHzMedium Wave (AM broadcast)
SW2.3 – 26.1 MHzShort Wave broadcast
FM87.5 – 108 MHzFM broadcast
VHF Air108 – 137 MHzAviation band
2m Ham144 – 148 MHz2 meter amateur band
70cm Ham420 – 450 MHz70 cm amateur band
HF LSB/USB1.8 – 30 MHzHF amateur bands (SSB)
HF CW1.8 – 30 MHzHF amateur bands (CW)

The app remembers your last frequency in each band and restores it when you return.

💾 Memory Bank

  • Save – Long-press an empty slot to store the current frequency and mode
  • Recall – Tap any saved slot to jump the rig straight to that frequency and mode
  • Capacity – 90 on-device slots, paginated 9 per page across 10 pages
  • Labels – Name a slot so its button shows the station or net instead of the raw frequency
  • Persistence – Held in platform secure storage on the device, independent of the server’s own 24-slot memory bank
Memory bank and S-meter
Memory bank with the signal-strength meter — recall stored frequencies while the S-meter tracks the rig

Step Sizes by Mode

ModeStep Size
AM10 kHz
FM100 kHz
SW5 kHz
MW10 kHz
LW1 kHz
LSB/USB1 kHz
CW100 Hz

📈 SDR Panadapter & Waterfall

The SDR page draws a live scope and scrolling waterfall from the server’s panadapter stream with SkiaSharp — the same SDL1 spectrum feed the desktop, web, and Home Assistant clients consume, so the picture matches on every surface. On iOS and Android the waterfall renders on the GPU (an SKGLView surface).

  • Multi-SDR slot picker – When the server has multiple SDR devices active, a Slot picker and Audio button appear above the waterfall. Select a slot to view its spectrum; the Audio button is blue when that slot is the listening source and red when it is not — tap to switch. The audio-active slot is also marked [A]. Hidden when only one device is active.
  • Per-slot memory – Gain, floor, contrast, reference level, zoom, palette, and the 2D / 3D choice are remembered separately for each slot; switching slots snaps the frequency scale to that slot’s current tuning.
  • Center mode – When enabled, panning shifts the SDR band (LO changes, rig marker stays centered). When disabled, panning moves the rig frequency marker.
  • Tap – In center mode, re-centers the band on the tapped frequency. In non-center mode, tunes the rig. Commands are routed to the selected slot.
  • Pinch-to-zoom – Zoom into the spectrum. Two-finger drag simultaneously pans the band.
  • Fullscreen – Double-tap for fullscreen with larger fonts and labels.
  • Long press – Sets the demod offset marker.
  • 3D waterfall (terrain view) – Toggle the waterfall between the flat 2D view and a rotatable 3D perspective terrain. Drag to orbit the camera. GPU-accelerated via an SKGLView surface, with palette, style, fog, and shading options.
  • Waterfall Ref (max-level) – A Ref slider sets the top of the waterfall color scale so strong signals reach the top of the palette instead of being clipped below full scale.
SDR 2D scope and waterfall
2D scope + waterfall with click-to-tune
SDR 2D waterfall with multiple signals
Several signals across the band in the 2D view
SDR 3D terrain waterfall with multiple signals
The same band as a rotatable 3D terrain
SDR 2D waterfall in landscape
Landscape — full-width 2D panadapter

🔢 Digital Decoders

The app includes server-side digital mode decoding for all eight modes — CW, RTTY, PSK31, FT8, SSTV, WEFAX, NAVTEX, and APRS. Switching mode broadcasts to every connected client.

Digital decoder panel
Decoder panel — eight-mode selector with live decoded text
CW decoder in landscape
Landscape — CW (Morse) decode
SSTV decoder in landscape
Landscape — SSTV image reception

Decode Modes

  • CW (Morse) – Real-time CW decoding up to 40 WPM
  • RTTY – Baudot decoding with auto-detect for baud rate and shift
  • PSK31 – Phase Shift Keying; 9 modes (BPSK-31/63/125, QPSK-L/U-31/63/125 with FEC), AFC, center frequency 200–3000 Hz, and squelch
  • FT8 – FT8/FT4 decodes relayed from an external WSJT-X instance running on the server machine (UDP port 2237)
  • SSTV – Slow Scan TV image reception with thumbnail and detail views
  • WEFAX – Weather facsimile decoder (IOC 576/288 at 60/120 LPM); same image-+-progress UI as SSTV
  • NAVTEX – Maritime safety message decoder (SITOR-B FEC, 100 baud, 170 Hz shift). Decoded characters stream to the text display.
  • APRS – AX.25 1200 baud Bell 202 AFSK packet radio. Decoded packets display source callsign, position, and beacon text.

FT8 Color Coding

FT8 messages are color-coded by signal strength (SNR) for easy identification:

SNR RangeColorSignal Quality
0 dB and aboveBright GreenStrong signal
-10 to -1 dBWhiteModerate signal
-15 to -11 dBOrangeWeak signal
Below -15 dBRedVery weak signal

SSTV Image Decoder

The SSTV decoder displays images transmitted over radio:

  • Thumbnail view – Small preview in the decoder panel
  • Detail view – Tap thumbnail for full-size image
  • Progress display – Shows decode progress percentage
  • Mode detection – Auto-detects mode or use forced mode
  • Save images – Save decoded images to device

Supported modes (19 total): Robot 36 / 72 / 8BW / 24BW, Martin M1 / M2, Scottie S1 / S2 / DX, PD 90 / 120 / 160 / 180 / 240 / 290, Wraase SC2-120 / SC2-180, Pasokon P3 / P5 / P7

💡 Tip

Server-side decoding is more accurate than client-side because it processes the original audio without network jitter or latency issues.

🔊 Transmit & Image TX

ShackLink Mobile is a full transmit client for the server’s shared TX engine. Incoming and outgoing traffic share one chat-style timeline; the server enforces a single-owner TX lock, so a send refused because another operator holds the key is greyed out rather than silently dropped.

  • Voice – Tap-to-toggle PTT (tap once to key, again to unkey) streams mic audio to the server’s token-authenticated voice uplink. A three-zone VU meter tracks your level while keyed.
  • CW / RTTY / PSK31 – Type into the compose box and send; the server’s encoders key the rig and mirror the transmitted text back into the timeline.
  • APRS – Compose and send AX.25 packets through the server’s APRS encoder.
  • Image TX – Pick a photo and transmit it over the air; the staged image previews before you commit the send.
Transmit panel
Transmit panel — mode picker, PTT, compose box, and the QSO timeline
Image TX panel
Image TX — stage a picture and send it over the air
CW transmit in landscape
Landscape — CW transmit with the QSO timeline
SSTV image transmit in landscape
Landscape — SSTV / image transmit

🎶 Audio Visualization

The app includes a high-performance spectrum analyzer and waterfall display for real-time audio visualization:

Audio visualization — waterfall mode
Waterfall + spectrum-overlay mode
Audio visualization — LED mode
Spectrum LED mode
Audio tab in landscape
Landscape — the full audio tab with spectrum + waterfall

Features

  • Spectrum Analyzer – Smooth curve display showing audio frequency content with semi-transparent fill
  • Waterfall Display – Scrolling spectrogram with color-coded signal intensity
  • Gain Control – Adjustable sensitivity (0.5x to 10x) for optimal display
  • Collapsible Panel – Tap header to expand/collapse the visualization
  • Mode-Aware Bandwidth – Display range adapts to radio mode (CW: 0-1kHz, SSB: 0-3kHz, FM: 0-6kHz)
  • 3D Waterfall (terrain view) – The waterfall can switch to a rotatable 3D perspective terrain rendered on the GPU. Drag to orbit the camera; a button toggles 2D / 3D. Style, fog, and shading options included.
  • Waterfall Palettes – 8 color schemes from the unified WaterfallPalette, shared across the 2D and 3D waterfalls and matched to the other ShackLink surfaces.

Color Scale

The waterfall uses a multi-color gradient to indicate signal strength:

ColorSignal Strength
Dark BlueVery weak / noise floor
BlueWeak signals
CyanModerate signals
GreenGood signals
YellowStrong signals
OrangeVery strong signals
RedPeak signals
WhiteMaximum intensity

Technical Details

  • FFT Size – 512 samples for detailed frequency resolution
  • Sample Rate – 12kHz audio stream from server
  • Refresh Rate – 30 FPS for smooth animation
  • Rendering – GPU-accelerated using SkiaSharp with direct bitmap manipulation

💡 Performance

The visualization uses SkiaSharp for GPU-accelerated rendering with direct pixel buffer access, providing smooth 30 FPS performance even on mobile devices.

🔌 Protocol Details

The mobile app communicates with the server using simple text commands over TCP:

Commands Sent by App

# Set frequency (Hz) FREQ:14074000 # Set mode MODE:USB # Select rig RIG:1

Messages Received from Server

# Frequency and mode update RIG:1:FREQ:14074000;MODE:USB # Radio status RIG:1:RADIO:ONLINE:IC-7300 RIG:1:RADIO:OFFLINE # Rig names RIGS:Rig 1|Rig 2|Rig 3|Rig 4

🔧 Troubleshooting

Cannot Connect (LAN)

  • Verify the server is running and radio is connected
  • Check IP address is correct (server IP, not radio IP)
  • Ensure your phone is on the same network as the server
  • Check firewall allows ports 8080, 8081, 8082, 8084, 8085 (and UDP 8081 for auto-detect) — Tools → Configure Firewall on the server creates the rules automatically

Cannot Connect (Remote)

  • Verify your tunnel / port-forward is reachable: open http://your-tunnel-host:8084 in a browser. The web client should load. If not, the network path is broken before the app even tries.
  • The unified-WebSocket transport needs /ws with WebSocket Upgrade headers passed through. Cloudflare Tunnel, Tailscale Funnel, and a default nginx + Let’s Encrypt setup all handle this. Some “lite” reverse proxies strip the upgrade headers — check the proxy’s docs.
  • If you connect briefly then disconnect: the secret is wrong. Open Tools → Security on the server, copy the secret, and paste it into the auth-secret prompt that appears when you re-enter a manual hostname.

Connection Drops

  • Move closer to your Wi-Fi router
  • Check for network interference
  • Disable battery optimization for the app
  • The app will automatically try to reconnect

Frequency Not Changing

  • Ensure radio shows “ONLINE” status on server
  • Check OmniRig is properly connected to the radio
  • Verify frequency is within the radio’s range
  • Check VFO is not locked on the radio

App Crashes on Startup

  • Update to the latest version
  • Clear app data and restart
  • Reinstall the application
  • Check device meets minimum requirements