APRS Message Format

Good news!

This site is slowly getting archived in favor of our new wider-community effort at Traquito.

Head over to our new site at Traquito to check out the $14 WSPR tracker, realtime maps/graphs, and other great resources!


You may want to build an APRS message.

I don't mean encoding a GPS location.

I mean building a low-level bit-by-bit sendable packet that will be identified properly by low-level tech like gates and repeaters, etc.

I've provided a source code implementation of the below on another page (here).

OSI Layers

Here are the lower levels of the OSI stack that correspond to all terminology relating to APRS.

The design behind APRS predated formalized OSI standardization and so not all of the layering is strictly intact in all places.

Documentation and resources tend to go into a lot of detail about things you don't need to care much about, like all the detail around HDLC and AX.25.

Below I'm going to outline the message structure as you need to care about it in a practical sense.

This does not cover the actual transmission of this data here (but I do elsewhere), because that's complex, and unrelated to the task of actually successfully building a message in the first place.

I will start from the bottom to the top of the OSI stack and move upwards, showing what the specs identify as message format structure.

I will link together those structures so you can see them in context.

Layer 1

This is a depiction of the Layer 1 frame structure for HDLC/Bell202.

I only mention it because you'll see this diagram around and I want to be clear about what I'm talking about.

We will care about the Frame Payload here.

Layer 2

This is a depiction of the Layer2 AX.25 frame structure.

This is what goes into the Frame Payload identified above.

The formatting of the Address fields is the most complex part here.

The Destination, Source, and the 0-or-more "Routing Path" Address fields are formatted using identical methodology.

Below is a description of how to format any of the Address fields.

Each Address field must be 7 bytes.

The format is <SIGN>[spaces]<SSID>

The callsign is left-aligned, occupying up to 6 characters.

Any callsign less than 6 characters is space-padded on the right.

The 7th byte is for the SSID, as well as many other bit flags.

The formatting of the actual data is:

SIGN bytes (6 bytes)

- each ascii character is shifted 1 bit to the left, allowing for the

  least-significant-bit to represent flag data.

SSID byte (1 byte)

- HRRSSIDS (this is the format of the bit flags, defined below)

  - H    - "has been repeated" - set to 0 as we're doing initial send

  - RR   - Reserved.  Set each bit to 1.

  - SSID - The actual binary SSID, 0-15.

  - S    - Stop bit.  Set to 1 if the final address field before Control byte, 0 otherwise.

The Control and PID (Protocol ID) fields are constants in practice.

Control = 0x03

PID = 0xF0

The "Information Field" is where APRS-specific formatted data goes (things like GPS locations, etc).

I don't cover that here since there are many resources out there dedicated to it.

Back to Layer 1 - Worrying about the Checksum (FCS)

The checksum should be calculated after all other fields in the Layer 2 message have been filled out.

There is an extra complication that the specs dictate that, unlike the rest of the fields, when transmitted in Layer 1 (physical) that the bits should be sent most-significant-bit first as opposed to all other fields.

The specifics of what is meant by the spec are ambiguous as written, but in my source code implementation the details get worked out and you, as the developer, just need to worry about streaming out the bits.