ship162 is a complete maritime tracking application that includes the rs162 Rust library for decoding AIS (Automatic Identification System) messages from binary feeds and NMEA sentences using the deku library for clean, declarative binary data parsing.
The library takes its inspiration from the Python pyais library and leverages deku to provide efficient, type-safe AIS message decoding. The major specificity compared to other implementations is the deku-based decoder, which enables clean bit-level parsing with compile-time guarantees.
The directions ambitioned by ship162 include:
- providing high-performance AIS decoding in Rust;
- offering efficient multi-receiver AIS decoding;
- serving real-time enriched maritime data to external applications;
- end-to-end demodulation and decoding from SDR hardware to structured data.
The ultimate goal is to create a complete maritime tracking solution that can receive raw radio signals and output structured AIS data, similar to what dump1090 does for aviation ADS-B messages.
- Complete AIS message support: Handles all standard AIS message types (1-27)
- NMEA sentence parsing: Full support for AIVDM/AIVDO messages with multi-fragment assembly
- Type-safe decoding: Leverages Rust's type system and deku for reliable parsing
- JSON serialization: Built-in serde support for easy data export
- Real-time processing: Efficient handling of live AIS data streams
- Multi-fragment messages: Automatic assembly of multi-sentence AIS messages
rtlsdr: Support for real-time demodulation from RTL-SDR USB dongles (enabled viadesperado).mqtt: Support for connecting to MQTT brokers (e.g., Finnish Digitraffic). Disabled by default.
- AIS-catcher in C++
- pyais in Python
- ais or nmea-parser in Rust
The key differentiator of ship162 is its use of deku for declarative binary parsing, providing both performance and correctness guarantees that are difficult to achieve with manual bit manipulation.
The long-term vision for ship162 is to become a complete end-to-end demodulation and decoding application that can:
- Receive raw RF signals from SDR hardware
- Demodulate AIS signals (161.975 MHz and 162.025 MHz)
- Decode NMEA sentences in real-time
- Provide Python and WebAssembly bindings
- Offer a complete maritime tracking solution
This will make ship162 the maritime equivalent of rs1090 for aviation tracking.
Run the following Cargo command in your project directory:
# Standard installation
cargo add rs162
# With MQTT support
cargo add rs162 --features mqtt
# With RTL-SDR support
cargo add rs162 --features rtlsdrOr add the following line to your Cargo.toml:
rs162 = "0.1.0" # check for the latest versionThe ship162 application supports TOML configuration files for defining multiple AIS data sources. This makes it easy to configure and manage different input sources without using command-line arguments.
The application searches for configuration files in the following locations (in priority order):
- Path specified by the
SHIP162_CONFIGenvironment variable $XDG_CONFIG_HOME/ship162/config.toml~/.config/ship162/config.toml
# Example configuration with multiple sources
# RTL-SDR device by index
[[sources]]
rtlsdr = { device = 0 }
gain = 49.6 # Recommended max gain for 162 MHz
bias_tee = true # Enable bias-tee if using powered antenna
# RTL-SDR device by serial number
[[sources]]
rtlsdr = { serial = "00000001" }
gain = 49.6
# RTL-SDR device by manufacturer/product filter
[[sources]]
rtlsdr = { manufacturer = "Realtek", product = "RTL2838UHIDIR" }
gain = 49.6
# SoapySDR device (e.g., PlutoSDR, LimeSDR)
[[sources]]
soapy = "driver=rtlsdr"
gain = 49.6
gain_element = "TUNER" # Optional: specify gain element
bias_tee = false
# PlutoSDR by IP address
[[sources]]
pluto = "192.168.2.1"
gain = 73.0 # Maximum gain for PlutoSDR
# TCP source (e.g., Norwegian Coastal Administration)
[[sources]]
tcp = "153.44.253.27:5631"
# TCP source with SSH tunnel (requires --features ssh)
# [[sources]]
# tcp = { host = "remote-ais-server.example.com", port = 5631, jump = "jumphost" }
# MQTT source (requires --features mqtt)
[[sources]]
mqtt = "mqtt://mqtt.digitraffic.fi"
# I/Q sample file
[[sources]]
iqfile = "/path/to/samples.cf32"RTL-SDR devices can be selected by:
- Device index:
rtlsdr = { device = 0 } - Serial number:
rtlsdr = { serial = "00000001" } - Manufacturer/Product:
rtlsdr = { manufacturer = "Realtek", product = "RTL2838UHIDIR" }
Common options:
gain: Gain in dB (recommended: 49.6 for max gain)bias_tee: Enable/disable bias-tee (default: false)
SoapySDR sources use a driver string:
soapy = "driver=rtlsdr"for RTL-SDR via SoapySDRsoapy = "driver=plutosdr"for PlutoSDR via SoapySDRsoapy = "driver=lime"for LimeSDR
Common options:
gain: Gain in dBgain_element: Gain element name (default: "TUNER")bias_tee: Enable/disable bias-tee
PlutoSDR sources require an IP address or URI:
pluto = "192.168.2.1"orpluto = "ip:192.168.2.1"
Common options:
gain: Gain in dB (recommended: 73.0 for AIS)
TCP sources connect to a remote AIS feed:
tcp = "host:port"- Simple TCP connectiontcp = { host = "hostname", port = 5631 }- Structured formattcp = { host = "hostname", port = 5631, jump = "jumphost" }- SSH tunneled connection (requires--features ssh)
SSH tunneling allows secure connections to remote AIS sources through jump hosts. This feature requires building with the ssh feature:
cargo build --release --features rtlsdr,sshConfiguration:
# TCP source with SSH tunnel
[[sources]]
tcp = { host = "remote-ais-server.example.com", port = 5631, jump = "jumphost.example.com" }SSH Setup:
SSH tunneling uses standard SSH configuration:
-
~/.ssh/config - SSH client configuration:
Host jumphost.example.com User myuser IdentityFile ~/.ssh/id_ed25519 -
~/.ssh/known_hosts - Host verification keys (populated automatically on first connection)
-
~/.ssh/id_* - SSH keys for authentication (generate with
ssh-keygen)
The jump parameter refers to a hostname in your ~/.ssh/config or a direct hostname that can be resolved.
MQTT sources connect to an MQTT broker (requires --features mqtt):
mqtt = "mqtt://broker.example.com"
No additional configuration options.
I/Q file sources read from a file containing raw I/Q samples:
iqfile = "/path/to/file.cf32"
No additional configuration options.
Create a configuration file at ~/.config/ship162/config.toml and run:
cargo run --release --features rtlsdr,soapyOr specify a custom configuration file location:
SHIP162_CONFIG=/path/to/config.toml cargo run --releaseSee config.toml.example in the repository for a complete example with documentation.
use rs162::decode::ais::Message;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Single NMEA sentence
let nmea = "!AIVDM,1,1,,B,15M67FC000G?ufbE`FepT@3n00Sa,0*5C";
let message = Message::from_nmea(&[nmea])?;
// Convert to JSON
let json = serde_json::to_string(&message)?;
println!("{}", json);
Ok(())
}use rs162::decode::ais::Message;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Multi-sentence Type 5 static and voyage data
let sentences = [
"!AIVDM,2,1,1,A,55?MbV02;H;s<HtKR20EHE:0@T4@Dn2222222216L961O5Gf0NSQEp6ClRp8,0*1C",
"!AIVDM,2,2,1,A,88888888880,2*25",
];
let message = Message::from_nmea(&sentences)?;
let json = serde_json::to_string(&message)?;
println!("{}", json);
Ok(())
}# See examples/nmea_file.rs for a complete file processor
cargo run --example nmea_file# See examples/nmea_tcp.rs for live AIS data processing
# Connects to Norwegian Coastal Administration's free AIS feed
cargo run --release --example nmea_tcp -- 153.44.253.27:5631 | \
jq -c '.message + .mmsi_info + {timestamp: (.timestamp | strftime("%Y-%m-%dT%H:%M:%SZ"))}'# See examples/iqfile.rs for processing I/Q sample files
cargo run --release --example iqfile | \
jq -c '.message + .mmsi_info + {timestamp: (.timestamp | strftime("%Y-%m-%dT%H:%M:%SZ"))}'# See examples/rtltcp.rs
rtl_tcp -a 127.0.0.1 -p 1234 -f 162M -s 288k -g 49.6
cargo run --release --example rtltcp | \
jq -c '.message + .mmsi_info + {timestamp: (.timestamp | strftime("%Y-%m-%dT%H:%M:%SZ"))}'Warning
Please read the following important note for Linux users: https://github.com/ccostes/rtl-sdr-rs#uload-kernel-modules
# See examples/rtlsdr.rs
cargo run --release --example rtlsdr | \
jq -c '.message + .mmsi_info + {timestamp: (.timestamp | strftime("%Y-%m-%dT%H:%M:%SZ"))}'
# See examples/rtlsdr_async.rs
cargo run --release --example rtlsdr_async | \
jq -c '.message + .mmsi_info + {timestamp: (.timestamp | strftime("%Y-%m-%dT%H:%M:%SZ"))}'The library implements:
- IEC 61162-1: Maritime navigation digital interfaces (NMEA 0183)
- ITU-R M.1371: Technical characteristics for AIS
- IEC 62320-1: AIS transponder equipment standards
Real-time AIS data is freely available from the Norwegian Coastal Administration:
- Host: 153.44.253.27
- Port: 5631
- Format: IEC 61162-1 (NMEA with timestamps)
- License: Norwegian license for public data
More information: https://www.kystverket.no/en/sea-transport-and-ports/ais/access-to-ais-data/
Note
You must compile the library or application with --features mqtt to access this source.
Real-time AIS data is available via MQTT from Finnish Digitraffic:
- Broker:
mqtt.digitraffic.fi - Topics:
vessels-v2/\<mmsi\>/metadatavessels-v2/\<mmsi\>/locationsvessels-v2/status
- Format: JSON messages containing AIS data
- License: "Kaikki Digitraffic -palvelun kautta jaettava tieto on koneluettavaa avointa dataa ja on käytettävissä Creative Commons 4.0 Nimeä -käyttöluvalla, mikä mahdollistaa uusien palveluiden ja ohjelmistojen kehittämisen." (machine translation: "All data distributed through the Digitraffic service is machine-readable open data and is available under the Creative Commons 4.0 Attribution license, which enables the development of new services and software.")
More information: https://www.digitraffic.fi/en/marine-traffic/
Most of the codebase has been generated with the assistance of Claude Sonnet 4, using specifications from:
- GPSD AIVDM documentation
- Test cases adapted from the pyais library
- ITU-R M.1371 specifications
Contributions are welcome! The project particularly benefits from:
- Real-world test cases and data samples
- Performance optimizations
- Documentation improvements
This project is licensed under the MIT License. See the license file for details.
