aprs.me/lib/parser/object.ex
2025-06-23 10:53:34 -05:00

70 lines
2.2 KiB
Elixir

# @dialyzer {:nowarn_function, parse: 1}
defmodule Parser.Object do
@moduledoc """
APRS object parsing.
"""
@doc """
Parse an APRS object string. Returns a struct or error.
"""
@spec parse(String.t()) :: map() | nil
def parse(<<";", object_name::binary-size(9), live_killed::binary-size(1), timestamp::binary-size(7), rest::binary>>) do
position_data =
case rest do
<<"/", latitude_compressed::binary-size(4), longitude_compressed::binary-size(4), symbol_code::binary-size(1),
cs::binary-size(2), compression_type::binary-size(1), comment::binary>> ->
try do
converted_lat =
Parser.CompressedPositionHelpers.convert_compressed_lat(latitude_compressed)
converted_lon =
Parser.CompressedPositionHelpers.convert_compressed_lon(longitude_compressed)
compressed_cs = Parser.CompressedPositionHelpers.convert_compressed_cs(cs)
base_data = %{
latitude: converted_lat,
longitude: converted_lon,
symbol_table_id: "/",
symbol_code: symbol_code,
comment: comment,
position_format: :compressed,
compression_type: compression_type
}
Map.merge(base_data, compressed_cs)
rescue
_ -> %{latitude: nil, longitude: nil, comment: comment, position_format: :compressed}
end
<<latitude::binary-size(8), sym_table_id::binary-size(1), longitude::binary-size(9), symbol_code::binary-size(1),
comment::binary>> ->
%{latitude: lat, longitude: lon} =
Parser.Position.parse_aprs_position(latitude, longitude)
%{
latitude: lat,
longitude: lon,
symbol_table_id: sym_table_id,
symbol_code: symbol_code,
comment: comment,
position_format: :uncompressed
}
_ ->
%{comment: rest, position_format: :unknown}
end
Map.merge(
%{
object_name: String.trim(object_name),
live_killed: live_killed,
timestamp: timestamp,
data_type: :object
},
position_data
)
end
def parse(data), do: %{data_type: :object, raw_data: data}
end