72 lines
2.5 KiB
Elixir
72 lines
2.5 KiB
Elixir
defmodule Augie.Sensor.GPS do
|
|
defstruct ~w[latitude longitude altitude heading speed satellites status]a
|
|
alias __MODULE__
|
|
|
|
@moduledoc """
|
|
Storage struct for GPS telemetry
|
|
"""
|
|
|
|
@type gps_status ::
|
|
:none | :established | :time_only | :std | :dgps | :rtk_float | :rtk_fixed | :pps
|
|
@type t :: %GPS{
|
|
latitude: float,
|
|
longitude: float,
|
|
altitude: float,
|
|
heading: float,
|
|
speed: float,
|
|
satellites: integer,
|
|
status: gps_status()
|
|
}
|
|
|
|
@doc """
|
|
Convert incoming telemetry into a structure.
|
|
"""
|
|
@spec build([integer | float]) :: {:ok, GPS.t()} | {:error, any}
|
|
def build([latitude, longitude, altitude, heading, speed, satellites, status])
|
|
when is_float(heading) and is_integer(satellites) do
|
|
with {:ok, latitude} <- convert_latitude(latitude),
|
|
{:ok, longitude} <- convert_longitude(longitude),
|
|
{:ok, altitude} <- convert_altitude(altitude),
|
|
{:ok, speed} <- convert_speed(speed),
|
|
{:ok, status} <- convert_status(status) do
|
|
{:ok,
|
|
%GPS{
|
|
latitude: latitude,
|
|
longitude: longitude,
|
|
altitude: altitude,
|
|
heading: heading,
|
|
speed: speed,
|
|
satellites: satellites,
|
|
status: status
|
|
}}
|
|
end
|
|
end
|
|
|
|
def build(_data), do: {:error, :bad_data}
|
|
|
|
# Convert `-412908200` into `-41.2908200`
|
|
defp convert_latitude(lat) when is_integer(lat), do: {:ok, lat / 10_000_000.0}
|
|
defp convert_latitude(_), do: {:error, :invalid_latitude}
|
|
|
|
# Convert `1747394892` into `174.7394892`
|
|
defp convert_longitude(long) when is_integer(long), do: {:ok, long / 10_000_000.0}
|
|
defp convert_longitude(_), do: {:error, :invalid_longitude}
|
|
|
|
# Convert altitude in centimeters into meters.
|
|
defp convert_altitude(altitude) when is_integer(altitude), do: {:ok, altitude / 100.0}
|
|
defp convert_altitude(_), do: {:error, :invalid_altitude}
|
|
|
|
# Convert speed in kilometers per hour into meters per second.
|
|
defp convert_speed(speed) when is_integer(speed), do: {:ok, speed * 1000.0 / 3600.0}
|
|
defp convert_speed(_), do: {:error, :invalid_speed}
|
|
|
|
# Convert status integer back into flag:
|
|
defp convert_status(0), do: {:ok, :none}
|
|
defp convert_status(1), do: {:ok, :established}
|
|
defp convert_status(2), do: {:ok, :time_only}
|
|
defp convert_status(3), do: {:ok, :std}
|
|
defp convert_status(4), do: {:ok, :dgps}
|
|
defp convert_status(5), do: {:ok, :rtk_float}
|
|
defp convert_status(6), do: {:ok, :rtk_fixed}
|
|
defp convert_status(_), do: {:error, :invalid_status}
|
|
end
|