From c750d5da172999bcea9d0637cf4c899d25952686 Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Wed, 1 Feb 2023 13:34:05 -0600 Subject: [PATCH] more parsing progress on compressed positions --- lib/aprs/convert.ex | 2 + lib/aprs/is/is.ex | 3 ++ lib/parser.ex | 90 +++++++++++++++++++++++++++++++----- lib/types/position.ex | 16 ++----- mix.exs | 3 +- mix.lock | 2 + test/aprs/convert_test.exs | 6 +++ test/parser/parser_test.exs | 9 ++++ test/types/position_test.exs | 22 +++++++++ 9 files changed, 129 insertions(+), 24 deletions(-) create mode 100644 test/types/position_test.exs diff --git a/lib/aprs/convert.ex b/lib/aprs/convert.ex index 00ced5c..47054b4 100644 --- a/lib/aprs/convert.ex +++ b/lib/aprs/convert.ex @@ -2,4 +2,6 @@ defmodule Aprs.Convert do def wind(speed, :ultimeter, :mph), do: speed * 0.0621371192 def temp(value, :ultimeter, :f), do: value * 0.1 + + def speed(value, :knots, :mph), do: Float.round(value * 1.15077945, 2) end diff --git a/lib/aprs/is/is.ex b/lib/aprs/is/is.ex index efb28e3..bca3c1b 100644 --- a/lib/aprs/is/is.ex +++ b/lib/aprs/is/is.ex @@ -208,6 +208,9 @@ defmodule Aprs.Is do # IO.inspect(parsed_message) # Logger.debug("SERVER:" <> message) + {:error, :invalid_packet} -> + Logger.debug("PARSE ERROR: invalid packet") + {:error, error} -> Logger.debug("PARSE ERROR: " <> error) diff --git a/lib/parser.ex b/lib/parser.ex index edcfb36..86d6ab2 100644 --- a/lib/parser.ex +++ b/lib/parser.ex @@ -36,9 +36,9 @@ defmodule Parser do rescue _ -> # Logger.debug("PARSE ERROR: " <> message) - # {:ok, file} = File.open("/home/graham/badpackets.txt", [:append]) - # IO.binwrite(file, message <> "\n\n") - # File.close(file) + {:ok, file} = File.open("./badpackets.txt", [:append]) + IO.binwrite(file, message <> "\n\n") + File.close(file) {:error, :invalid_packet} end end @@ -161,7 +161,7 @@ defmodule Parser do [:ok, lat, lon] end - defp convert_to_base91(<>) do + def convert_to_base91(<>) do [v1, v2, v3, v4] = to_charlist(value) (v1 - 33) * 91 * 91 * 91 + (v2 - 33) * 91 * 91 + (v3 - 33) * 91 + v4 end @@ -236,16 +236,44 @@ defmodule Parser do end def parse_position_without_timestamp( - _aprs_messaging?, - <<_dti::binary-size(1), "/", _latitude::binary-size(4), _longitude::binary-size(4), - _sym_table_id::binary-size(1), _cs::binary-size(2), _compression_type::binary-size(1), - _comment::binary>> = message + aprs_messaging?, + <<_dti::binary-size(1), "/", latitude::binary-size(4), longitude::binary-size(4), + sym_table_id::binary-size(1), _cs::binary-size(2), _compression_type::binary-size(1), + comment::binary>> = message ) do - # {:ok, file} = File.open("badpackets.txt") - # IO.puts(file, message) + # {:ok, file} = File.open("./compressed.txt", [:append]) + # IO.binwrite( + # file, + # message <> + # "\n" <> + # "aprs_messaging?: #{aprs_messaging?}\n" <> + # "dti: #{dti}\n" <> + # "latitude: #{latitude}\n" <> + # "longitude: #{longitude}\n" <> + # "sym_table_id: #{sym_table_id}\n" <> + # "cs: #{cs}\n" <> + # "compression_type: #{compression_type}\n" <> + # "comment: #{comment}\n\n" + # ) # File.close(file) - + # convert_compressed_cs(cs) |> IO.inspect() Logger.debug("TODO: PARSE COMPRESSED LAT/LON: " <> message) + + converted_lat = convert_compressed_lat(latitude) + converted_lon = convert_compressed_lon(longitude) + position = Position.from_decimal(converted_lat, converted_lon) + # converted_cs = convert_compressed_cs(cs) + + %{ + latitude: converted_lat, + longitude: converted_lon, + position: position, + symbol_table_id: sym_table_id, + # symbol_code: symbol_code, + comment: comment, + data_type: :position, + aprs_messaging?: aprs_messaging? + } end def parse_position_with_timestamp( @@ -508,4 +536,44 @@ defmodule Parser do # defp convert_ultimeter_humidity(hum) do # hum * 10 # end + + def convert_compressed_lat(lat) do + [l1, l2, l3, l4] = to_charlist(lat) + 90 - ((l1 - 33) * 91 ** 3 + (l2 - 33) * 91 ** 2 + (l3 - 33) * 91 + l4 - 33) / 380_926 + end + + def convert_compressed_lon(lon) do + [l1, l2, l3, l4] = to_charlist(lon) + -180 + ((l1 - 33) * 91 ** 3 + (l2 - 33) * 91 ** 2 + (l3 - 33) * 91 + l4 - 33) / 190_463 + end + + def convert_compressed_cs(cs) do + [c, s] = to_charlist(cs) + c = c - 33 + s = s - 33 + + case c do + x when x in ?!..?z -> + # compressed speed/course value + # speed is returned in knots + %{ + course: s * 4, + speed: Convert.speed(1.08 ** s - 1, :knots, :mph) + } + + ?Z -> + # pre-calculated radio range + %{ + range: 2 * 1.08 ** s + } + + _ -> + IO.inspect(cs, label: "not parsable") + + %{ + course: 0, + speed: 0 + } + end + end end diff --git a/lib/types/position.ex b/lib/types/position.ex index 275c757..494f1fc 100644 --- a/lib/types/position.ex +++ b/lib/types/position.ex @@ -17,8 +17,6 @@ defmodule Parser.Types.Position do aprs_latitude = aprs_latitude |> String.replace(" ", "0") |> String.pad_leading(9, "0") aprs_longitude = aprs_longitude |> String.replace(" ", "0") |> String.pad_leading(9, "0") - # Logger.debug("#{aprs_latitude} #{aprs_longitude}") - <> = aprs_latitude <> = aprs_longitude @@ -28,16 +26,6 @@ defmodule Parser.Types.Position do <> = convert_garbage_to_zero(longitude) - # %Position{ - # lat_degrees: lat_deg |> String.replace(".", "") |> String.to_integer(), - # lat_minutes: lat_min |> String.replace(".", "") |> String.to_integer(), - # lat_fractional: convert_fractional(lat_fractional), - # lat_direction: convert_direction(lat_direction), - # lon_degrees: lon_deg |> String.replace(".", "") |> String.to_integer(), - # lon_minutes: lon_min |> String.replace(".", "") |> String.to_integer(), - # lon_fractional: convert_fractional(lon_fractional), - # lon_direction: convert_direction(lon_direction) - # } try do lat = Geocalc.DMS.to_degrees(%Geocalc.DMS{ @@ -61,6 +49,10 @@ defmodule Parser.Types.Position do end end + def from_decimal(latitude, longitude) do + %{latitude: latitude, longitude: longitude} + end + defp convert_garbage_to_zero(value) do try do _ = String.to_float(value) diff --git a/mix.exs b/mix.exs index de70d3f..5ab1e16 100644 --- a/mix.exs +++ b/mix.exs @@ -73,7 +73,8 @@ defmodule Aprs.MixProject do {:faker, "~> 0.17.0", only: [:dev, :test]}, {:stream_data, "~> 0.5", only: [:dev, :test]}, {:mix_test_watch, "~> 1.1", only: [:dev, :test]}, - {:sobelow, "~> 0.8", only: :dev} + {:sobelow, "~> 0.8", only: :dev}, + {:codepagex, "~> 0.1.6"} ] end diff --git a/mix.lock b/mix.lock index abf16a7..0afec3b 100644 --- a/mix.lock +++ b/mix.lock @@ -3,9 +3,11 @@ "bunt": {:hex, :bunt, "0.2.1", "e2d4792f7bc0ced7583ab54922808919518d0e57ee162901a16a1b6664ef3b14", [:mix], [], "hexpm", "a330bfb4245239787b15005e66ae6845c9cd524a288f0d141c148b02603777a5"}, "castore": {:hex, :castore, "0.1.22", "4127549e411bedd012ca3a308dede574f43819fe9394254ca55ab4895abfa1a2", [:mix], [], "hexpm", "c17576df47eb5aa1ee40cc4134316a99f5cad3e215d5c77b8dd3cfef12a22cac"}, "certifi": {:hex, :certifi, "2.9.0", "6f2a475689dd47f19fb74334859d460a2dc4e3252a3324bd2111b8f0429e7e21", [:rebar3], [], "hexpm", "266da46bdb06d6c6d35fde799bcb28d36d985d424ad7c08b5bb48f5b5cdd4641"}, + "codepagex": {:hex, :codepagex, "0.1.6", "49110d09a25ee336a983281a48ef883da4c6190481e0b063afe2db481af6117e", [:mix], [], "hexpm", "1521461097dde281edf084062f525a4edc6a5e49f4fd1f5ec41c9c4955d5bd59"}, "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"}, "comeonin": {:hex, :comeonin, "5.3.3", "2c564dac95a35650e9b6acfe6d2952083d8a08e4a89b93a481acb552b325892e", [:mix], [], "hexpm", "3e38c9c2cb080828116597ca8807bb482618a315bfafd98c90bc22a821cc84df"}, "connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"}, + "convertat": {:hex, :convertat, "1.1.0", "00c125f00a2e06be74d27df5a6b93f9b2d7c27aaa6ecb41d96f009ee7d7bd978", [:mix], [], "hexpm", "603229c43df6769f2166c78c5c3f31316390bf6e19fa8e15f02026170ab51a79"}, "cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"}, "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"}, "cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"}, diff --git a/test/aprs/convert_test.exs b/test/aprs/convert_test.exs index d6c381d..e7ab5a2 100644 --- a/test/aprs/convert_test.exs +++ b/test/aprs/convert_test.exs @@ -13,4 +13,10 @@ defmodule Aprs.ConvertTest do assert Convert.temp(55, :ultimeter, :f) == 5.5 end end + + describe "speed/3" do + test "converts knots to mph" do + assert Convert.speed(55, :knots, :mph) == 63.29 + end + end end diff --git a/test/parser/parser_test.exs b/test/parser/parser_test.exs index b3d0918..65ab4c9 100644 --- a/test/parser/parser_test.exs +++ b/test/parser/parser_test.exs @@ -233,4 +233,13 @@ defmodule Parser.ParserTest do } end end + + describe "convert_compressed_cs/1" do + # !! + # I! + # Y" + test "1" do + assert Parser.convert_compressed_cs("Y$") == %{course: 12, speed: 0.3} + end + end end diff --git a/test/types/position_test.exs b/test/types/position_test.exs new file mode 100644 index 0000000..9006317 --- /dev/null +++ b/test/types/position_test.exs @@ -0,0 +1,22 @@ +defmodule Parser.Types.PositionTest do + use ExUnit.Case + alias Parser.Types.Position + + describe "from_aprs/2" do + test "1" do + assert Position.from_aprs("3339.13N", "11759.13W") == %{ + latitude: 33.652166666666666, + longitude: -117.9855 + } + end + end + + describe "from_decimal/2" do + test "1" do + assert Position.from_decimal(33.652166666666666, -117.9855) == %{ + latitude: 33.652166666666666, + longitude: -117.9855 + } + end + end +end