Sidereon.GNSS.RTCM (Sidereon v0.31.2)

Copy Markdown View Source

RTCM 3.x differential-GNSS stream decoding.

RTCM 10403.x is the dominant wire format for real-time GNSS correction and observation streams. This module is a thin wrapper over the sidereon-core rtcm sans-I/O decoder: a forgiving frame layer that syncs on the 0xD3 preamble and verifies the CRC-24Q, and a canonical message decoder.

decode_messages/1 scans a whole byte buffer and returns every CRC-valid message; decode_frame/1 decodes the single frame at the start of a buffer.

Message format

Each decoded message is a {type, fields} pair where type is one of :station_coordinates (1005/1006), :antenna_descriptor (1007/1008/1033), :gps_ephemeris (1019), :glonass_ephemeris (1020), :beidou_ephemeris (1042), :qzss_ephemeris (1044), :galileo_fnav_ephemeris (1045), :galileo_inav_ephemeris (1046), :msm (MSM4/MSM7 observations), or :unsupported (any other number, preserved verbatim). The fields map carries the raw transmitted integer fields; station coordinates additionally carry the scaled :x_m / :y_m / :z_m / :antenna_height_m values.

Summary

Functions

Decode every CRC-valid RTCM 3 frame in a byte buffer.

Decode the single RTCM 3 frame that begins at the start of bytes.

Decode one RTCM message body.

Decode every CRC-valid RTCM 3 frame in a byte buffer.

Decode every CRC-valid RTCM 3 frame and return messages plus stream diagnostics.

Construct a supported RTCM 3 message and return its message body.

Construct a supported RTCM 3 message and return its complete frame.

Construct a supported RTCM 3 message from a {type, fields} pair and encode it into a complete transport frame (preamble, length, body, CRC-24Q).

Return the RINEX LLI bit constants used by the RTCM MSM derivation helpers.

Return the message number from one RTCM message body.

Minimum continuous-lock time in milliseconds for an MSM lock indicator.

Elapsed milliseconds between two raw MSM epoch-time fields for one system.

Derive per-cell LLI rows by running a core lock-time tracker over MSM maps.

RINEX observation-code suffix for an MSM signal id, or nil if reserved.

Types

message()

@type message() :: {message_type(), map()}

message_type()

@type message_type() ::
  :station_coordinates
  | :antenna_descriptor
  | :gps_ephemeris
  | :glonass_ephemeris
  | :beidou_ephemeris
  | :qzss_ephemeris
  | :galileo_fnav_ephemeris
  | :galileo_inav_ephemeris
  | :msm
  | :unsupported

Functions

decode(bytes)

@spec decode(binary()) :: {:ok, [message()]} | {:error, term()}

Decode every CRC-valid RTCM 3 frame in a byte buffer.

decode_frame(bytes)

@spec decode_frame(binary()) ::
  {:ok, %{message_number: integer(), frame_len: integer(), body: binary()}}
  | {:error, term()}

Decode the single RTCM 3 frame that begins at the start of bytes.

Verifies the preamble and the CRC-24Q. Returns {:ok, %{message_number: n, frame_len: bytes, body: binary}} or {:error, reason} for a missing preamble, a truncated buffer, or a CRC mismatch. The body can be fed back through decode_messages/1 after re-framing.

decode_message(body)

@spec decode_message(binary()) :: {:ok, message()} | {:error, term()}

Decode one RTCM message body.

decode_messages(bytes)

@spec decode_messages(binary()) :: {:ok, [message()]} | {:error, term()}

Decode every CRC-valid RTCM 3 frame in a byte buffer.

Frames whose CRC fails or whose body cannot be decoded are skipped, and the scan resynchronizes on the next preamble (the forgiving stream contract for a noisy feed). Returns {:ok, [{type, fields}, ...]} in stream order, or {:error, reason}.

decode_stream(bytes)

@spec decode_stream(binary()) ::
  {:ok,
   %{
     messages: [message()],
     diagnostics: %{resync_bytes: non_neg_integer(), skipped_frames: [map()]}
   }}
  | {:error, term()}

Decode every CRC-valid RTCM 3 frame and return messages plus stream diagnostics.

The message list matches decode_messages/1. Diagnostics include skipped resynchronization bytes and CRC-valid frames whose typed body decode failed.

derive_lli(previous_min_lock_time_ms, elapsed_ms, current_min_lock_time_ms, half_cycle?)

@spec derive_lli(integer() | nil, integer() | nil, integer() | nil, boolean()) ::
  non_neg_integer()

Derive the RINEX LLI digit for one signal cell.

Pass elapsed_ms as nil for the first observation. When elapsed_ms is an integer, previous_min_lock_time_ms may be nil to represent a previous reserved indicator.

encode(arg)

@spec encode(message()) :: {:ok, binary()} | {:error, term()}

Construct a supported RTCM 3 message and return its message body.

encode_frame(body)

@spec encode_frame(message() | binary()) :: {:ok, binary()} | {:error, term()}

Construct a supported RTCM 3 message and return its complete frame.

encode_message(message)

@spec encode_message(message()) :: {:ok, binary()} | {:error, term()}

Construct a supported RTCM 3 message from a {type, fields} pair and encode it into a complete transport frame (preamble, length, body, CRC-24Q).

type is one of the supported message_type/0 atoms (:unsupported cannot be constructed). fields is a map of the raw transmitted fields, the same shape decode_messages/1 produces for that type (the derived :x_m/:y_m/:z_m station outputs are ignored when present, so a decoded map round-trips directly). Returns {:ok, frame_binary} or {:error, reason}.

The output frame feeds back through decode_messages/1, so construct -> encode -> decode reproduces the same message fields.

lli_bits()

@spec lli_bits() :: %{loss_of_lock: 1, half_cycle: 2}

Return the RINEX LLI bit constants used by the RTCM MSM derivation helpers.

message_number(body)

@spec message_number(binary()) :: {:ok, integer()} | {:error, term()}

Return the message number from one RTCM message body.

minimum_lock_time_ms(kind, indicator)

@spec minimum_lock_time_ms(String.t(), integer()) ::
  {:ok, non_neg_integer() | nil} | {:error, term()}

Minimum continuous-lock time in milliseconds for an MSM lock indicator.

kind is "msm4" or "msm7".

msm_epoch_dt_ms(system, previous, current)

@spec msm_epoch_dt_ms(String.t(), integer(), integer()) ::
  {:ok, non_neg_integer()} | {:error, term()}

Elapsed milliseconds between two raw MSM epoch-time fields for one system.

msm_lli(messages)

@spec msm_lli([map()]) :: {:ok, [[map()]]} | {:error, term()}

Derive per-cell LLI rows by running a core lock-time tracker over MSM maps.

The input is a list of decoded MSM field maps, in stream order. The result is one list of %{satellite_id, signal_id, lli, min_lock_time_ms} maps per input message.

msm_signal_rinex_code(system, signal_id)

@spec msm_signal_rinex_code(String.t(), integer()) ::
  {:ok, String.t() | nil} | {:error, term()}

RINEX observation-code suffix for an MSM signal id, or nil if reserved.