ACARS Integration

📡 ACARS Message Handling

Real-time aircraft datalink message ingestion, decoding, and analysis


🚀 Quick Start

Get ACARS messages flowing in under 5 minutes:

📋

Prerequisites

  • Docker and Docker Compose installed
  • SDR hardware (RTL-SDR or similar)
  • SkySpy Django backend running
# 1. Add ACARS services to your docker-compose.yml
# 2. Start the stack
docker-compose up -d

# 3. Start the ACARS listener
python manage.py run_acars

# 4. Verify messages are flowing
curl http://localhost:8000/api/v1/acars/status/

Success!

You should see "running": true in the response. Messages will appear in the web UI within seconds.


📖 Overview

SkySpy receives, decodes, stores, and displays real-time ACARS (Aircraft Communications Addressing and Reporting System) and VDL2 (VHF Data Link Mode 2) messages from aircraft. The system integrates with popular SDR-based decoders via the acars_router container.

✨ Key Features

🔌

Dual Protocol Support

ACARS (VHF) and VDL Mode 2 on separate UDP ports

Real-time Streaming

Socket.IO-based live message delivery to connected clients

🏷️

Message Enrichment

Automatic airline identification and label decoding

🔬

libacars Integration

Advanced decoding of FANS-1/A, CPDLC, and MIAM messages

🔄

Deduplication

LRU cache-based duplicate message filtering (30s TTL)

📊

Statistics & Analytics

Comprehensive message analytics and trending


🏗️ Architecture

System Data Flow

flowchart TB
    subgraph Hardware["📻 SDR Hardware"]
        SDR[RTL-SDR / AirSpy]
    end

    subgraph Decoders["🔧 Decoders"]
        ACARS[acarsdec<br/>VHF ACARS]
        VDL2[vdlm2dec<br/>VDL Mode 2]
        DUMP[dumpvdl2<br/>VDL Mode 2]
    end

    subgraph Router["🔀 Message Router"]
        AR[acars_router<br/>UDP Forwarder]
    end

    subgraph SkySpy["✈️ SkySpy Backend"]
        UDP5550["UDP :5550<br/>ACARS"]
        UDP5555["UDP :5555<br/>VDL2"]
        SVC[AcarsService<br/>Django]
    end

    subgraph Storage["💾 Storage & Delivery"]
        DB[(PostgreSQL)]
        WS[Socket.IO<br/>Broadcast]
        API[REST API]
    end

    SDR --> ACARS
    SDR --> VDL2
    SDR --> DUMP

    ACARS --> AR
    VDL2 --> AR
    DUMP --> AR

    AR --> UDP5550
    AR --> UDP5555

    UDP5550 --> SVC
    UDP5555 --> SVC

    SVC --> DB
    SVC --> WS
    SVC --> API

Message Processing Pipeline

sequenceDiagram
    participant D as Decoder
    participant R as acars_router
    participant U as UDP Listener
    participant S as AcarsService
    participant C as Cache
    participant DB as PostgreSQL
    participant WS as Socket.IO

    D->>R: JSON Message
    R->>U: Forward UDP
    U->>S: Parse JSON
    S->>S: Normalize Format
    S->>C: Check Duplicate
    alt New Message
        C-->>S: Not Found
        S->>S: Enrich (airline, label)
        S->>DB: Store Message
        S->>WS: Broadcast
    else Duplicate
        C-->>S: Found (skip)
    end

📨 Message Types

🏷️ Label Categories

ACARS messages are identified by two-character label codes. SkySpy categorizes these into logical groups:

🛫

OOOI Events Out/Off/On/In

Flight phase tracking from gate departure to arrival

LabelNameDescriptionEmoji
10OutAircraft departed gate🚪
11OffAircraft took off🛫
12OnAircraft landed🛬
13InAircraft arrived at gate🅿️
80OOOIGeneric OOOI event✈️
📍

Position Reports

Real-time aircraft location and navigation data

LabelNameDescriptionEmoji
H1DatalinkHF datalink / FANS-1/A message📡
H2DatalinkHF datalink message📡
2PProgressFlight progress report📈
22ReportPeriodic position report🗺️
C1PositionPosition report📌
🌤️

Weather

Meteorological requests and data

LabelNameDescriptionEmoji
QA - QFWeatherWeather requests and data🌡️
Q0 - Q2WeatherWeather link messages📊
44WeatherWeather request/data☁️
21AdvisoryWeather advisory⚠️
30 - 39WeatherMETAR, TAF, PIREP, SIGMET🌪️
⚙️

Operational

Flight operations and clearances

LabelNameDescriptionEmoji
15ETAEstimated Time of Arrival⏱️
16DepartureDeparture message🛫
17ArrivalArrival message🛬
20RequestOperational request📋
33ATISAutomatic Terminal Info📢
B1 - B9ClearanceDeparture/oceanic clearances
🔧

System/Technical

Aircraft systems monitoring

LabelNameDescriptionEmoji
SASystemSystem/general message💻
SQSquitterGround station ID📶
5ZACMSAircraft condition monitoring🔍
83FuelFuel request/data
50 - 59MaintenanceEngine, APU, system reports🛠️
🎯

CPDLC/FANS

Controller-pilot data communications

LabelNameDescriptionEmoji
CACPDLCController-Pilot Data Link🎙️
CRCPDLCCPDLC Request📞
A0 - A7FANSFANS-1/A application messages🌐
AD - AFADS-CAutomatic Dependent Surveillance📍
💬

Free Text

General text communications

LabelNameDescriptionEmoji
AAFree TextGeneral free text message📝
ABFree TextFree text reply↩️
FA - FFFree TextVarious free text formats💬
_dDemandDemand mode message

🔌 Data Ingestion

UDP Listener Configuration

# Default ports
ACARS_UDP_PORT = 5550  # Standard ACARS messages
VDLM2_UDP_PORT = 5555  # VDL Mode 2 messages

Processing Steps

flowchart LR
    A["1️⃣ Reception"] --> B["2️⃣ Parsing"]
    B --> C["3️⃣ Normalization"]
    C --> D["4️⃣ Deduplication"]
    D --> E["5️⃣ Enrichment"]
    E --> F["6️⃣ Storage"]
    F --> G["7️⃣ Broadcast"]
StepDescription
1️⃣UDP datagram received on port 5550 (ACARS) or 5555 (VDL2)
2️⃣JSON payload decoded from UTF-8
3️⃣Message format normalized to common schema
4️⃣LRU cache check (30-second TTL)
5️⃣Airline info extracted, label decoded, libacars parsing
6️⃣Persisted to PostgreSQL database
7️⃣Sent to Socket.IO subscribers

🚀 Starting the Service

# Using management command
python manage.py run_acars

# With custom ports
python manage.py run_acars --acars-port 5550 --vdlm2-port 5555

# Disable one listener
python manage.py run_acars --no-vdlm2

# Verbose logging
python manage.py run_acars -v 2

📋 Message Formats

Decoder Comparison

Featureacarsdecvdlm2decdumpvdl2
ProtocolACARS VHFVDL2VDL2
Frequencies129-137 MHz136 MHz band136 MHz band
Output FormatFlat JSONNested JSONNested JSON
ICAO Fieldicaoavlc.src.addravlc.src.addr
TimestampUnix floatsec/usec objectsec/usec object
Signal Levellevel (dB)sig_level (dB)sig_level (dB)

📥 Input: acarsdec Format

{
  "timestamp": 1703001234.567,
  "freq": 131.55,
  "channel": 0,
  "icao": "ABC123",
  "tail": "N12345",
  "flight": "UAL456",
  "label": "SA",
  "text": "POSITION REPORT...",
  "level": -32,
  "error": 0
}

📥 Input: dumpvdl2 Format

{
  "vdl2": {
    "t": { "sec": 1703001234, "usec": 567000 },
    "freq": 136975000,
    "sig_level": -28,
    "avlc": {
      "src": { "addr": "ABC123" },
      "acars": {
        "reg": ".N12345",
        "flight": "AAL123",
        "label": "SA",
        "msg_text": "POSITION REPORT..."
      }
    }
  }
}

📤 Output: Normalized Schema

FieldTypeDescription
timestampfloatUnix timestamp
sourcestringacars or vdlm2
channelstringReceiver channel
frequencyfloatFrequency in MHz
icao_hexstringAircraft ICAO hex address
registrationstringAircraft registration (tail)
callsignstringFlight callsign
labelstringACARS message label
block_idstringMessage block identifier
msg_numstringMessage sequence number
ackstringAcknowledgment flag
modestringACARS mode
textstringMessage text content
signal_levelfloatSignal strength (dB)
error_countintDecoding errors
station_idstringReceiving station ID

💾 Database Model

class AcarsMessage(models.Model):
    SOURCE_CHOICES = [
        ('acars', 'ACARS'),
        ('vdlm2', 'VDL Mode 2'),
    ]

    timestamp = models.DateTimeField(db_index=True)
    source = models.CharField(max_length=10, choices=SOURCE_CHOICES)
    channel = models.CharField(max_length=10, blank=True, null=True)
    frequency = models.FloatField(blank=True, null=True)
    icao_hex = models.CharField(max_length=10, db_index=True)
    registration = models.CharField(max_length=20, db_index=True)
    callsign = models.CharField(max_length=10, db_index=True)
    label = models.CharField(max_length=10, db_index=True)
    block_id = models.CharField(max_length=5)
    msg_num = models.CharField(max_length=10)
    ack = models.CharField(max_length=5)
    mode = models.CharField(max_length=5)
    text = models.TextField()
    decoded = models.JSONField(blank=True, null=True)
    signal_level = models.FloatField()
    error_count = models.IntegerField()
    station_id = models.CharField(max_length=50)

    class Meta:
        db_table = 'acars_messages'
        indexes = [
            models.Index(fields=['icao_hex', 'timestamp']),
            models.Index(fields=['label', 'timestamp']),
        ]
        ordering = ['-timestamp']

🏷️ Message Enrichment

Each message is automatically enriched with additional metadata:

✈️

Airline Information

{
    "airline": {
        "icao": "UAL",
        "iata": "UA",
        "name": "United Airlines",
        "flight_number": "456"
    }
}
🏷️

Label Information

{
    "label_info": {
        "name": "Position Report",
        "description": "Aircraft position and progress reports"
    }
}
🔍

Decoded Text (when applicable)

{
    "decoded_text": {
        "message_type": "Position Report",
        "position": {"lat": 45.1234, "lon": -122.5678},
        "altitude_ft": 35000,
        "airports_mentioned": ["KSEA", "KJFK"]
    }
}

🔄 Deduplication

Messages are deduplicated using an LRU cache with a 30-second TTL:

# Hash computation uses:
# - Timestamp (rounded to second)
# - ICAO hex address
# - Message label
# - First 50 characters of text

cache = LRUCache(maxsize=10000, ttl_seconds=30)

🌐 API Reference

Base URL

/api/v1/acars/

📋 List Messages

GET /api/v1/acars/

Query Parameters:

ParameterTypeDefaultDescription
hoursint24Time range filter
sourcestring-Filter by source (acars/vdlm2)
icao_hexstring-Filter by aircraft ICAO
callsignstring-Filter by callsign
labelstring-Filter by message label
limitint-Maximum results

Response:

{
  "messages": [
    {
      "id": 12345,
      "timestamp": "2024-01-15T10:30:00Z",
      "source": "acars",
      "frequency": 131.55,
      "icao_hex": "ABC123",
      "callsign": "UAL456",
      "label": "SA",
      "text": "ETA KJFK 1430Z",
      "airline": {
        "icao": "UAL",
        "name": "United Airlines"
      },
      "label_info": {
        "name": "System",
        "description": "System message"
      }
    }
  ],
  "count": 1,
  "filters": {"hours": 24}
}

📊 Get Statistics

GET /api/v1/acars/stats/

Response:

{
  "total_messages": 15420,
  "last_hour": 245,
  "last_24h": 5832,
  "by_source": {
    "acars": 3200,
    "vdlm2": 2632
  },
  "top_labels": [
    {"label": "SA", "count": 1245},
    {"label": "H1", "count": 892}
  ]
}

📈 Get Message Breakdown

GET /api/v1/acars/stats/breakdown/

Query Parameters:

ParameterTypeDefaultDescription
hoursint24Time range
use_cachebooltrueUse cached stats

Response:

{
  "total_messages": 5832,
  "time_range_hours": 24,
  "by_source": {"acars": 3200, "vdlm2": 2632},
  "by_label": [
    {
      "label": "SA",
      "count": 1245,
      "name": "System",
      "description": "System message",
      "category": "system"
    }
  ],
  "by_category": [
    {
      "category": "oooi",
      "name": "OOOI Events",
      "count": 890,
      "percentage": 15.3
    }
  ],
  "top_frequencies": [
    {"frequency": 131.55, "frequency_mhz": "131.550", "count": 2100}
  ]
}

🏢 Get Airline Statistics

GET /api/v1/acars/stats/airlines/

Response:

{
  "airlines": [
    {
      "airline_icao": "UAL",
      "airline_iata": "UA",
      "airline_name": "United Airlines",
      "message_count": 456,
      "unique_flights": 12
    }
  ],
  "total_with_airline_info": 4500,
  "total_messages": 5832
}

📉 Get Message Trends

GET /api/v1/acars/stats/trends/

Query Parameters:

ParameterTypeDefaultDescription
hoursint24Time range
intervalstringhourInterval type (hour/day)

Response:

{
  "intervals": [
    {
      "timestamp": "2024-01-15T10:00:00Z",
      "total": 245,
      "acars": 145,
      "vdl2": 100,
      "unique_aircraft": 45,
      "unique_flights": 38
    }
  ],
  "peak_interval": {
    "timestamp": "2024-01-15T14:00:00Z",
    "count": 312
  },
  "hourly_distribution": [
    {"hour": 0, "count": 89},
    {"hour": 1, "count": 67}
  ]
}

🔴 Get Receiver Status

GET /api/v1/acars/status/

Response:

{
  "running": true,
  "acars": {
    "total": 15420,
    "last_hour": 245,
    "errors": 12,
    "duplicates": 89
  },
  "vdlm2": {
    "total": 12350,
    "last_hour": 198,
    "errors": 5,
    "duplicates": 45
  },
  "buffer_size": 100
}

🏷️ Get Label Reference

GET /api/v1/acars/labels/

Response:

{
  "labels": {
    "H1": {"name": "Datalink", "description": "HF datalink message"},
    "SA": {"name": "System", "description": "System message"}
  },
  "sources": {
    "acars": "ACARS (VHF)",
    "vdlm2": "VDL Mode 2"
  }
}

🖥️ Frontend Integration

Socket.IO Connection

sequenceDiagram
    participant Client as 🖥️ Browser
    participant WS as 🔌 Socket.IO
    participant Django as 🐍 Django

    Client->>WS: Connect io('/acars')
    WS->>Django: Establish connection
    Django-->>Client: Connection ACK

    Client->>WS: socket.emit('subscribe', {topic: 'messages'})

    loop Real-time Updates
        Django->>WS: New ACARS message
        WS->>Client: acars:message event
    end

Socket.IO Connection:

import { io } from 'socket.io-client';

const socket = io('https://hostname/acars', {
  path: '/socket.io/',
  transports: ['websocket', 'polling']
});

Subscribe to Messages:

socket.emit('subscribe', { topic: 'messages' });

📡 Events

EventDescription
acars:messageNew ACARS message received
acars:snapshotInitial message batch on connect

Listening for Events:

socket.on('acars:message', (data) => {
  console.log('New ACARS message:', data);
});

socket.on('acars:snapshot', (data) => {
  console.log('Initial messages:', data);
});

useAircraftAcars Hook

import { useAircraftAcars } from './hooks/useAircraftAcars';

const {
  acarsMessages,        // Array of messages
  acarsHours,           // Time range filter
  setAcarsHours,        // Update time range
  acarsCompactMode,     // Display mode
  setAcarsCompactMode,  // Toggle compact mode
  acarsQuickFilters,    // Active category filters
  setAcarsQuickFilters, // Update filters
  acarsLoaded,          // Loading state
} = useAircraftAcars({
  hex: 'ABC123',
  baseUrl: 'http://localhost:8000',
  callsign: 'UAL456',
  activeTab: 'acars',
  wsRequest,
  wsConnected,
});

🏷️ Message Categories (Frontend)

const quickFilterCategories = {
  position: {
    name: 'Position',
    labels: ['C1', 'SQ', '47', '2Z', 'AD', 'AE']
  },
  weather: {
    name: 'Weather',
    labels: ['15', '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '44', '80', '81', '83', '3M', '3S']
  },
  oooi: {
    name: 'OOOI',
    labels: ['10', '11', '12', '13', '14', '16', '17']
  },
  operational: {
    name: 'Operational',
    labels: ['H1', 'H2', '5Z', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', 'B1', 'B2', 'B9']
  },
  freetext: {
    name: 'Free Text',
    labels: ['AA', 'AB', 'FA', 'FF', 'F3', 'F5', 'F7']
  },
  maintenance: {
    name: 'Maintenance',
    labels: ['50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '5A', '5U']
  },
};

AcarsTab Component Features

⏱️

Time Range Selector

Filter messages by time (1h to 7 days)

🔀

View Toggle

Compact or expanded message display

🏷️

Quick Filters

Category-based filtering chips

📜

Message List

Scrollable list with expand/collapse

🔍

Decoded Data

Displays enriched message information


🔧 External Decoder Integration

Integration Architecture

flowchart LR
    subgraph Decoders["🔧 SDR Decoders"]
        A[acarsdec]
        V[vdlm2dec]
        D[dumpvdl2]
    end

    subgraph Router["🔀 acars_router"]
        R[UDP Aggregator]
    end

    subgraph SkySpy["✈️ SkySpy"]
        S5550[":5550 ACARS"]
        S5555[":5555 VDL2"]
    end

    A -->|UDP| R
    V -->|UDP| R
    D -->|UDP| R
    R -->|UDP| S5550
    R -->|UDP| S5555

acars_router Configuration

# docker-compose.yml
services:
  acars_router:
    image: ghcr.io/sdr-enthusiasts/acars_router:latest
    environment:
      # Input ports (receive from decoders)
      - AR_LISTEN_UDP_ACARS=5550
      - AR_LISTEN_UDP_VDLM2=5555
      # Output to SkySpy
      - AR_SEND_UDP_ACARS=skyspy:5550
      - AR_SEND_UDP_VDLM2=skyspy:5555
    ports:
      - "5550:5550/udp"
      - "5555:5555/udp"

acarsdec Configuration

acarsdec:
  image: ghcr.io/sdr-enthusiasts/docker-acarsdec:latest
  environment:
    - FEED_ID=MY-STATION
    - FREQUENCIES=130.025;130.425;130.450;131.125;131.550
    - OUTPUT_SERVER=acars_router:5550

dumpvdl2 / vdlm2dec Configuration

vdlm2dec:
  image: ghcr.io/sdr-enthusiasts/docker-vdlm2dec:latest
  environment:
    - FEED_ID=MY-STATION
    - FREQUENCIES=136.650;136.700;136.800;136.975
    - OUTPUT_SERVER=acars_router:5555
💡

Direct Integration

Skip acars_router for simpler setups:

acarsdec:
  environment:
    - OUTPUT_SERVER=skyspy:5550

vdlm2dec:
  environment:
    - OUTPUT_SERVER=skyspy:5555

🔬 libacars Integration

SkySpy integrates with libacars for advanced message decoding.

Supported Formats

🌐

FANS-1/A ADS-C

Automatic Dependent Surveillance - Contract

🎙️

FANS-1/A CPDLC

Controller-Pilot Data Link Communications

📦

MIAM

Media Independent Aircraft Messaging

✈️

Airline-Specific

Various proprietary message formats

Decodable Labels

decodable_labels = {
    "H1", "H2",           # FANS-1/A
    "SA", "S1", "S2",     # System address
    "AA", "AB", "AC",     # ARINC 622
    "BA", "B1"-"B6",      # Various airline formats
    "_d", "2Z", "5Z",     # MIAM compressed
}

Usage

from skyspy.services.libacars_binding import (
    decode_acars_apps,
    is_available,
    MsgDir,
)

if is_available():
    result = decode_acars_apps(
        label="H1",
        text="...",
        direction=MsgDir.AIR_TO_GROUND,
        use_cache=True
    )

Performance Features

FeatureDescription
🗄️ LRU CacheDecoded results cached to avoid redundant processing
Circuit BreakerAutomatic error recovery and rate limiting
📊 Prometheus MetricsExport decoding statistics

⚙️ Configuration

Django Settings

# skyspy_django/skyspy/settings.py

# UDP listener ports
ACARS_UDP_PORT = int(os.environ.get('ACARS_UDP_PORT', 5550))
VDLM2_UDP_PORT = int(os.environ.get('VDLM2_UDP_PORT', 5555))

# Message retention (for cleanup tasks)
ACARS_RETENTION_DAYS = int(os.environ.get('ACARS_RETENTION_DAYS', 30))

# Cache settings
ACARS_STATS_CACHE_TIMEOUT = 120  # seconds

Environment Variables

VariableDefaultDescription
ACARS_UDP_PORT5550UDP port for ACARS messages
VDLM2_UDP_PORT5555UDP port for VDL2 messages
ACARS_RETENTION_DAYS30Days to retain messages
LIBACARS_DISABLEDfalseDisable libacars decoding

Docker Compose

services:
  skyspy:
    environment:
      - ACARS_UDP_PORT=5550
      - VDLM2_UDP_PORT=5555
      - ACARS_RETENTION_DAYS=30
    ports:
      - "5550:5550/udp"
      - "5555:5555/udp"

🧪 Testing

Mock ACARS Service

A mock ACARS service is available for development and testing:

cd test/acars-mock
docker build -t acarshub-mock .
docker run -d \
  --name acarshub-mock \
  -p 8080:8080 \
  -p 5550:5550/udp \
  -p 5555:5555/udp \
  -e MOCK_ENABLED=true \
  -e RELAY_HOST=skyspy \
  -e RELAY_PORT=5550 \
  acarshub-mock

Mock Features

FeatureDescription
📨 Realistic MessagesCreates authentic ACARS/VDL2 messages
📍 Position ReportsUses real aircraft positions when available
🔀 Multiple FormatsGenerates both acarsdec and dumpvdl2 formats
🖥️ Web InterfaceMonitor at http://localhost:8080
Socket.IO StreamingReal-time message feed
💉 Message InjectionPOST custom messages via API

Mock API Endpoints

EndpointMethodDescription
/api/statsGETService statistics
/api/messagesGETRecent messages
/api/mock/startPOSTStart mock generation
/api/mock/stopPOSTStop mock generation
/api/injectPOSTInject custom message

Unit Tests

# Run ACARS service tests
python manage.py test skyspy.tests.test_services_acars

# Run with coverage
pytest skyspy/tests/test_services_acars.py --cov=skyspy.services.acars

Test Coverage

  • LRU cache operations and TTL expiration
  • Message hash computation and deduplication
  • Format normalization (ACARS and VDL2)
  • Frequency conversion (Hz to MHz)
  • Statistics tracking
  • Message storage and broadcasting
  • Service lifecycle (start/stop)

🚨 Troubleshooting

No Messages Received

⚠️

Problem

The ACARS listener is running but no messages appear

Checklist:

  1. Check UDP ports: Ensure ports 5550/5555 are accessible
  2. Verify decoder output: Check acarsdec/vdlm2dec logs
  3. Check acars_router: Verify forwarding configuration
  4. Firewall: Ensure UDP traffic is allowed
# Test UDP connectivity
nc -u localhost 5550 <<< '{"test": true}'

High Duplicate Count

ℹ️

Information

Duplicates are normal when multiple receivers pick up the same message

  • The 30-second TTL window filters most duplicates
  • Check if multiple decoders are forwarding the same messages
  • Consider adjusting LRU_CACHE_SIZE for high-traffic environments

libacars Not Working

Diagnostic

Check if libacars is available and functioning

from skyspy.services.libacars_binding import is_available, get_backend

print(f"Available: {is_available()}")
print(f"Backend: {get_backend()}")

Database Growth

⚠️

Problem

Database size growing rapidly

Solution:

# Check message count
from skyspy.models import AcarsMessage
print(AcarsMessage.objects.count())

# Manual cleanup (older than 30 days)
from datetime import timedelta
from django.utils import timezone
cutoff = timezone.now() - timedelta(days=30)
AcarsMessage.objects.filter(timestamp__lt=cutoff).delete()
💡

Tip

Set ACARS_RETENTION_DAYS environment variable to automate cleanup


📚 Glossary

TermDefinition
ACARSAircraft Communications Addressing and Reporting System
VDL2VHF Data Link Mode 2
OOOIOut/Off/On/In - Flight phase events
CPDLCController-Pilot Data Link Communications
ADS-CAutomatic Dependent Surveillance - Contract
FANS-1/AFuture Air Navigation System
MIAMMedia Independent Aircraft Messaging
libacarsC library for decoding ACARS message payloads

🔗 Related Resources

ResourceDescription
SDR Enthusiasts ACARS HubComplete ACARS receiving solution
acars_routerMessage aggregation and forwarding
libacarsC library for ACARS decoding
acarsdecMulti-channel ACARS decoder
dumpvdl2VDL Mode 2 decoder