Building a Mobile SAME/FM Transmitter with Flutter and HackRF

Hey Forgers! Sarah here, pulling back the curtain on a recent project that pushed our limits: building a mobile app with Flutter to turn an Android phone + HackRF One into a portable SAME/FM transmitter.

On the surface, it sounds cool – build a custom weather radio alert sender! In practice? It was a deep dive into the surprisingly complex world of radio, signal processing, and cross-platform development.

Today, I want to talk about the grind, the head-scratching moments, and what we learned wrestling with FM modulation in both Go and Dart.


The Vision: A Mobile SAME Transmitter

The idea was simple:

  • Build a Flutter app that could generate Specific Area Message Encoding (SAME) alerts (the distinctive tones/data bursts you hear on NOAA Weather Radio).
  • Transmit them using a HackRF One connected to an Android phone.

This wasn’t about broadcasting fake alerts—it was about creating a robust tool for education, testing emergency equipment, and understanding how these systems work.


Phase 1: The Go Experiment (A Promising Detour)

Before Flutter became the main focus, we initially explored Go for the core signal processing.

Why Go?
Its concurrency model and performance are fantastic for CPU-intensive tasks like generating complex radio signals.

The approach:

  1. Generate SAME data from an alert message.
  2. Turn that data into AFSK audio.
  3. Modulate the audio into an FM signal.
  4. Send it to the HackRF for transmission.

Getting AFSK working in Go was fairly straightforward. The real challenge came with FM modulation.

Tiny errors in frequency and phase handling produced distorted, unreadable signals. Debugging meant hours of watching spectrum analyzers, tweaking parameters, and chasing floating-point precision issues.

While results were promising, the integration with Flutter felt clunky. We wanted something more cohesive.


Phase 2: Dart + Flutter (The Final Frontier)

Flutter was the obvious choice for the UI, but this meant porting all the signal generation logic to Dart.

At first, we worried: “Dart is single-threaded—can it handle real-time signal generation?”
Turns out, yes—with careful optimization.

UI Wins

  • Building dropdowns, sliders, and event code lists in Flutter was seamless.
  • The real challenge was re-creating the FM modulation logic in Dart.

Technical Pain Points

  • Phase drift across long bursts would ruin the signal if not carefully tracked.
  • Integer overflow had to be managed so HackRF would accept clean I/Q samples.
  • Real-time performance required balancing heavy processing with keeping the UI responsive.
  • Plugin quirks forced us to carefully manage app initialization.

The Breakthrough: Back to Fundamentals

What finally made things work was returning to the core mathematics of FM modulation—getting frequency, phase, and signal continuity precise and consistent.

Once that foundation was solid, the HackRF accepted the samples, and radios decoded the SAME alerts cleanly.


Lessons Learned

  • Radio is Hard (and Fun): SDR requires precision—tiny mistakes create huge problems.
  • Go vs Dart for DSP: Go is powerful for performance, but Dart integrates better with Flutter.
  • Separation of Concerns Matters: Cleanly separating signal logic from UI code made development manageable.
  • Debugging Tools are Essential: A spectrum analyzer is a must-have when working with radio.

Final Thoughts

This project blended mobile UI development with low-level radio signal generation.

It showed off Flutter’s versatility and the power of open-source SDR hardware like the HackRF One.


Happy Hacking,
Sarah