This repository has been archived on 2024-06-24. You can view files and clone it, but cannot push or open issues or pull requests.
augie/webapp/lib/augie/sensors/gps.ex

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