samedec: Yet Another Decoder for SAME/EAS

Over-the-air weather alerts for your desktop or RPi.

This binary crate provides a digital demodulator and decoder program for Specific Area Message Encoding (SAME). It can be used as a drop-in replacement for multimon-ng's EAS mode in most cases.

The demodulation and decoding functions are published separately as the sameold library crate.

Background

SAME is commonly used to distribute weather alerts in the United States and Canada. It was originally developed for use with broadcast stations that carry analog audio signals, such as:

These stations participate in an emergency alerting network known as the Emergency Alert System, which disseminates alerts to the general public.

SAME messages are transmitted in place of the station's normal programming as an audio-only message. SAME messages include a digital header which separates them from the station's normal programming. The digital header is also sent in-band—encoded with an analog modulation to preserve it. SAME headers are modulated using two-level frequency-shift keying (FSK) and sent at a baud rate of 520.83 Hz.

Disclaimer

This crate is dual-licensed MIT and Apache 2.0. Read these licenses carefully as they may affect your rights.

This crate has not been certified as a weather radio receiver or for any other purpose. The author strongly discourages its use in any safety-critical applications. Always have at least two methods available for receiving weather alerts.

Getting Started

bash cargo install samedec

You will first need to recover baseband audio from a radio or television station which broadcasts SAME signals. Not all stations transmit SAME signals, and not all stations transmit them all the time.

NWR transmitters are not guaranteed to relay messages from civil authorities, such as warnings about wildfires, volcanic activity, or law enforcement emergencies. Your state's EAS Plan document may specify if NWR transmitters will carry such messages.

To feed samedec, obtain the audio signal that you would normally listen to. You can do this in any number of ways:

Via Analog Audio

You can use an analog audio "line out" from a hardware receiver, such as a weather radio, FM radio, or a scanner. Connect the "line out" port to your soundcard's "line in" jack.

You will need a way to pipe audio from your soundcard into samedec. You can install sox on most platforms:

bash rec -q -t raw -r 22.5k -e signed -b 16 -c 1 - | samedec --rate 22050

samedec takes input as 1-channel (mono), signed 16-bit integers, in platform-native endianness. This is equivalent to Rust's i16 format and is sometimes referred to in your audio drivers as s16ne.

The sampling --rate you set in samedec must match the sampling rate of the signal you are piping in. samedec's demodulator will be designed for whatever --rate you request, and it can work with a variety of sampling rates. We recommend using at least 8000 Hz. Higher sampling rates will cause samedec to use more CPU and I/O throughput, but the difference may not be particularly important on most systems.

On linux, you can obtain piped audio with either parec (PulseAudio) or arecord (ALSA). Both are preinstalled on most desktop distributions.

bash parec --channels 1 --format s16ne --rate 22050 --latency-msec 500 \ | samedec -r 22050

Via a Software-Defined Radio

Use any compatible SDR software to demodulate and recover passband audio from a station of interest. You will need a way to pipe passband audio into samedec.

samedec is not an FM demodulator and cannot accept IQ samples. You need to demodulate the passband audio signal and feed that into samedec.

For FM stations specifically, you will want to use mono-only decoding (if available) and the correct deemphasis filter.

General Advice

Regardless of input method, you will need a clean audio input with minimal noise. Ideally, you should have a signal that is nearly "full quieting," with no noise or static. SAME lacks modern error correction techniques and was designed to operate on links with plenty of signal-to-noise ratio. If the station you are receiving doesn't sound "good," see if you can find a closer one.

Be sure not to overdrive your soundcard or other input device. Check the incoming signal levels in your sound control panel or other program to ensure that they are not anywhere close to saturating. SAME digital headers are sent at no less than 80% modulation, and they may be louder than regular programming.

If the signal is too quiet, it is usually better to increase the volume of the sending device (i.e., radio) than it is to command large gain or volume levels with your soundcard. High volume levels may activate amplifiers that add unwanted noise. You may have to experiment a bit to find the correct volume levels. If available, use a "line input" port and not a microphone or headset port.

Always test your decoding setup! Stations which transmit EAS messages are required to transmit at least one message per week. If after a full week of listening you do not receive at least one message, something with your setup is broken.

Console Output

Decoding a sample message from Wikimedia Commons. Running:

bash sox 'Same.wav' -t raw -r 22.5k -e signed -b 16 -c 1 - | \ samedec -r 22050

should produce the following output:

txt ZCZC-EAS-RWT-012057-012081-012101-012103-012115+0030-2780415-WTSP/TV- NNNN NNNN NNNN

When samedec receives a SAME message, the message is printed to stdout. The printout uses the SAME ASCII encoding that is transmitted over the air.

Exactly one message is printed per line. Only messages are printed. SAME headers which indicate the beginning of a message are prefixed with ZCZC. Some validation is performed to ensure that headers have the correct format, but they may still contain invalid dates or unknown event codes.

SAME messages are always transmitted three times for redundancy. When decoding the message header, samedec will use all three transmissions together to improve decoding. Only one line will be output for the ZCZC header.

SAME trailers which indicate the end of message are output as NNNN. The trailers are not subject to the same error-correction process as the headers. All trailers which successfully decode will print an NNNN line. Up to three of these lines will be printed per SAME message. This decoding strategy permits end of message to be detected more quickly.

dsame is a python decoder which can produce human-readable text from this output. The sameold crate also understands how to parse message fields.

Child Processes

bash … | samedec -r 22050 -- play -q -t raw -r 22.5k -e signed -b 16 -c 1 -

samedec can spawn child processes to handle message audio.

Arguments to samedec which follow the ending -- will be interpreted as a child process to spawn for each SAME message received. The first argument ("play" above) is interpreted as an executable name. The usual rules for your platform apply with regards to $PATH discovery and the requirement that the executable bit be set. The remaining arguments will be passed to the executable, verbatim, without further interpretation by samedec.

One child process is spawned per SAME message received. The child is spawned just as soon as samedec finishes decoding the SAME header, and it will run until samedec receives a SAME end-of-message.

The child process will receive "passthrough" message audio on its standard input. Input samples which are provided to samedec will be provided to the child process, verbatim, at the input rate. The entire SAME message will be streamed to the child process. At the conclusion of the message, the child process standard input is closed.

The example above will play any SAME message received on your system speakers, via sox's play command.

What Good Is This?

You can use child processes to selectively play back or store SAME message audio. You can even compress the audio and email it, but beware: SAME messages can be up to two minutes long. For some emergencies which require quick response, two minutes is too long to wait.

Child Environment

The child process receives the following additional environment variables:

Design Requirements for Child Processes

samedec provides child processes with input samples synchronously, via blocking calls. Child processes spawned by samedec MUST have the following behavior:

  1. Children must read OR close their standard inputs. Failure to do this will temporarily block samedec from making progress until the child exits.

  2. Children which read from standard input must EXIT promptly when they reach end of file. Failure to do this will temporarily block samedec from making progress until the child exits.

Child processes should avoid starting long-running foreground jobs which might block for extended periods of time. The following sections provide examples which use bash scripting. You can use any language you want for the child process.

Example: Ignoring the Input

```bash

!/bin/bash

close standard input to ignore it

exec 0>/dev/null

echo "I got a ${SAMEDEC_EVENT}!" ```

Here, we close the standard input to avoid blocking samedec. Your script file must have the execute bit set (chmod +x …).

Example: Conditional Playback

```bash

!/bin/bash

[ "${SAMEDEC_SIGNIFICANCE}" = "W" ] || exit 0

exec pacat --channels 1 --format s16ne \ --rate "${SAMEDEC_RATE}" --latency-msec 500 "$@" ```

The above script will use pulseaudio (on linux) to play back any message which has a significance level of Warning (W). We use exec to replace the running shell with pacat. --rate "${SAMEDEC_RATE}" tells pacat what the sampling rate is. The "$@" is a bashism which passes the remaining input arguments to the script to pacat as arguments.

If you name this script ./play_on_warn.sh, then an example invocation of samedec is:

bash sox 'Same.wav' -t raw -r 22.5k -e signed -b 16 -c 1 - | \ samedec -r 22050 -- ./play_on_warn.sh

Example: Compress and Save

```bash

!/bin/bash

outfile="$(date +%s)${SAMEDECORG}${SAMEDECEVT}${SAMEDECSIGNIFICANCE}${SAMEDECISSUETIME}.ogg"

exec sox -q -t raw -r "${SAMEDEC_RATE}" -e signed -b 16 -c 1 - \ -t ogg -C-1 "$outfile" ```

Example invocation, assuming the script is named ./save.sh.

bash sox 'Same.wav' -t raw -r 22.5k -e signed -b 16 -c 1 - | \ samedec -r 22050 -- ./save.sh

Demo Mode

Invoke samedec with the --demo option to act as if a SAME header with event code "DMO" was received. The message will be printed to the console, and the child process (if any) will be spawned. The child will run for eight seconds before being terminated with a SAME "end of message." At the conclusion of the demo, samedec will exit. This mode is useful for testing your child process and other event handlers.

During the demo, audio fed into samedec will be fed through to the child process. A source of audio is still required to run the demo mode, but you can pipe in from /dev/zero if you want.

The sameold library considers the "DMO" event code to have a severity level of Warning (SAMEDEC_SIGNIFICANCE=W).

Debugging and Troubleshooting

This crate includes pretty_env_logger. You can request more verbose output with -v. Use up to three times -vvv to increase the verbosity level. Log messages are printed to stderr.

If you have a recording of a signal that you think should demodulate, but doesn't, please open an new issue on github. Either attach or link to your recording.

Please read our contributing guidelines before opening any issues or PRs.