Overview

Asterix is a binary data format, developed and maintained by eurocontrol.

The major problem with the original specifications is that they are provided in a form of free text (PDF files). As a consequence, the very first step in every asterix project is to retype the specifications to a parsable form. And this is what this project is all about.

Project content

This project contains:

Asterix definitions

In this project, the asterix definitions are stored and maintained in a compact text based parsable form. The intention of this format is to be:

Example definition snippet:

asterix 008 "Monoradar Derived Weather Information"
edition 1.2
date 2014-08-24
preamble
    Surveillance data exchange.

items

    000 "Message Type"
        definition
            This Data Item allows for a more convenient handling of the messages
            at the receiver side by further defining the type of transaction.
        element 8
            table
                1: Polar vector
                2: Cartesian vector of start point/length
                3: Contour record
                4: Cartesian start point and end point vector
                254: SOP message
                255: EOP message

    010 "Data Source Identifier"
        definition
            Identification of the radar station from which the data are received.
        group
            SAC "System Area Code"
                element 8
                    raw
            SIC "System Identification Code"
                element 8
                    raw
        remark
            Note:
                The defined SACs are on the EUROCONTROL ASTERIX website
                (www.eurocontrol.int/asterix)
    ...

See the structure description for more details.

How to use it?

The specifications are provided in various formats.

If you are creating new categories, consider contributing definitions to the upstream repository.

Example: simplify specification with python script

This example converts asterix specification to a simpler form, with some nonessential information removed from the structure. Where the specification is context dependent, it is converted to a default value (this is not exactly according to the original specification, but it allows much simpler struture and the problem can be handled manually in the application code if required - that is: hardcoding the exceptional cases).

Input and output are both in json format.

# -- convert.py script

import sys
import json

def split(obj):
    return (obj['tag'], obj['contents'])

def unsplit(tag, contents):
    return {'tag': tag, 'contents': contents}

def handle_number(obj):
    """Convert precise number structure to int or float"""
    t, cont = split(obj)
    if t == 'NumInt':
        return cont
    elif t == 'NumDiv':
        a = handle_number(cont['numerator'])
        b = handle_number(cont['denominator'])
        return float(a) / float(b)
    elif t == 'NumPow':
        return pow(cont['base'], cont['exponent'])
    else:
        raise Exception('unexpected', t)

def handle_rule(handler, obj):
    """Handle ContextFree/Dependent rule.
    In this example, ignore dependency and use 'default' rule.
    This handler requires another handler for the internal structure."""
    t, cont = split(obj)
    if t == 'ContextFree':
        return handler(cont)
    elif t == 'Dependent':
        return handler(cont['default'])
    else:
        raise Exception('unexpected', t)

def handle_signedness(obj):
    t, cont = split(obj)
    if t == 'Signed':
        return True
    elif t == 'Unsigned':
        return False
    else:
        raise Exception('unexpected', t)

def handle_content(obj):
    t, cont = split(obj)
    if t == 'ContentQuantity':
        return unsplit('quantity', {
            'lsb': handle_number(cont['lsb']),
            'signed': handle_signedness(cont['signedness']),
        })
    return unsplit('other', None)

def handle_variation(obj):
    t, cont = split(obj)
    if t == 'Element':
        rv = {
            'bits': cont['bitSize'],
            'content': handle_rule(handle_content, cont['rule']),
        }
    elif t == 'Group':
        rv = [handle_item(i) for i in cont]
    elif t == 'Extended':
        rv = [handle_item(i) if i else None for i in cont]
    elif t == 'Repetitive':
        rv = {
            'type': cont['type'],
            'variation': handle_variation(cont['variation']),
        }
    elif t == 'Explicit':
        rv = None
    elif t == 'Compound':
        rv = [handle_nonspare(i) if i else None for i in cont]
    else:
        raise Exception('unexpected', t)
    return unsplit(t, rv)

def handle_item(obj):
    t, cont = split(obj)
    if t == 'Spare':
        rv = cont
    elif t == 'Item':
        rv = handle_nonspare(cont)
    else:
        raise Exception('unexpected', t)
    return unsplit(t, rv)

def handle_nonspare(obj):
    return {
        'name': obj['name'],
        'variation': handle_rule(handle_variation, obj['rule']),
    }

def handle_uap_item(obj):
    t, cont = split(obj)
    if t == 'UapItem':
        return cont
    return None

def handle_uap(obj):
    t, cont = split(obj)
    if t == 'Uap':
        return unsplit(t, [handle_uap_item(i) for i in cont])
    elif t == 'Uaps':
        return unsplit(t, [(name,
            [handle_uap_item(i) for i in lst]) for name, lst in cont['cases']])
    else:
        raise Exception('unexpected', t)

def handle_asterix(obj):
    t, cont = split(obj)
    if t == 'AsterixBasic':
        rv = {
            'category': cont['category'],
            'edition': cont['edition'],
            'catalogue': [handle_nonspare(i) for i in cont['catalogue']],
            'uap': handle_uap(cont['uap']),
        }
    elif t == 'AsterixExpansion':
        rv = {
            'category': cont['category'],
            'edition': cont['edition'],
            'fspecByteSize': cont['fspecByteSize'],
            'items': [handle_nonspare(i) for i in cont['items']],
        }
    else:
        raise Exception('unexpected', t)
    return unsplit(t, rv)

# main
infile=sys.argv[1]
with open(infile) as f:
    obj1 = json.loads(f.read())
obj2 = handle_asterix(obj1)
print(json.dumps(obj2, indent=4))

Download and convert one specification:

# download
src=https://zoranbosnjak.github.io/asterix-specs/specs/
curl $src/cat001/cats/cat1.4/definition.json > original.json

# convert
python3 convert.py original.json > simple.json
ls -l original.json simple.json

Related projects

If you’re using asterix-specs definition files in your project (directly or indirectly) and the source code is available, your are welcome to notify project maintainer, to be added to the list.