Implement named data groups.
authorSiraaj Khandkar <siraaj@khandkar.net>
Mon, 5 Oct 2015 09:57:14 +0000 (05:57 -0400)
committerSiraaj Khandkar <siraaj@khandkar.net>
Mon, 5 Oct 2015 09:57:14 +0000 (05:57 -0400)
README.md
include/x_plane_data_group_lat_lon_alt.hrl [new file with mode: 0644]
include/x_plane_data_group_pitch_roll_heading.hrl [new file with mode: 0644]
include/x_plane_data_group_speeds.hrl [new file with mode: 0644]
rebar.config
src/x_plane_data.app.src
src/x_plane_data_group_lat_lon_alt.erl [new file with mode: 0644]
src/x_plane_data_group_pitch_roll_heading.erl [new file with mode: 0644]
src/x_plane_data_group_speeds.erl [new file with mode: 0644]
src/x_plane_data_named.erl [new file with mode: 0644]
test/x_plane_data_SUITE.erl

index 2de6895..b417370 100644 (file)
--- a/README.md
+++ b/README.md
@@ -16,14 +16,19 @@ Examples
 ### Parse data packet
 
 ```erlang
-{ok, {Index, Groups}} = x_plane_data_raw:of_bin(XPlaneDataPacket),
+{ok, {64=Index, GroupsRaw}=DataRaw} = x_plane_data_raw:of_bin(XPlaneDataPacket),
 ```
 
 ### Access parsed data
 
+#### Raw
+
+At this stage, only the structure of the packet was parsed. No attempt at
+interpreting the values have been made:
+
 ```erlang
 % Speeds are in group 3
-{3, Speeds} = lists:keyfind(3, 1, Groups),
+{3, Speeds} = lists:keyfind(3, 1, GroupsRaw),
 { VindKias
 , VindKeas
 , VtrueKtas
@@ -35,7 +40,7 @@ Examples
 } = Speeds,
 
 % Pitch roll and headings values are in group 17
-{17, PitchRollHeadings} = lists:keyfind(17, 1, Groups),
+{17, PitchRollHeadings} = lists:keyfind(17, 1, GroupsRaw),
 { PitchDeg
 , RollDeg
 , HdingTrue
@@ -47,6 +52,53 @@ Examples
 } = PitchRollHeadings,
 ```
 
+#### Named
+
+Here we identify what each of the numbered groups mean in a given X-Plane
+version. Right now only X-Plane 10 is supported and I only identified 3 groups
+so far:
+
+- index: `3` , name: `speeds`
+- index: `17`, name: `pitch_roll_heading`
+- index: `20`, name: `lat_lon_alt`
+
+Unidentified groups (with index other than what is listed above) will be
+absent from the list of named groups (think of `x_plane_data_named:of_raw/1` as
+a filter), so you'll have to access their raw version, if needed.
+
+##### Identify
+```erlang
+{ok, {x_plane_data_v10, GroupsNamed}} = x_plane_data_named:of_raw(DataRaw),
+```
+
+##### Access
+```erlang
+-include_lib("x_plane_data_group_lat_lon_alt.hrl").
+-include_lib("x_plane_data_group_pitch_roll_heading.hrl").
+-include_lib("x_plane_data_group_speeds.hrl").
+
+...
+
+{speeds, #x_plane_data_group_speeds
+    { vind_kias   = VindKias
+    , vind_keas   = VindKeas
+    , vtrue_ktas  = VtrueKtas
+    , vtrue_ktgs  = VtrueKtgs
+    , vind_mph    = VindMph
+    , vtrue_mphas = VtrueMphas
+    , vtrue_mphgs = VtrueMphgs
+    }
+} = lists:keyfind(speeds, 1, GroupsNamed),
+
+{pitch_roll_heading, #x_plane_data_group_pitch_roll_heading
+    { pitch_deg  = PitchDeg
+    , roll_deg   = RollDeg
+    , hding_true = HdingTrue
+    , hding_mag  = HdingMag
+    }
+} = lists:keyfind(pitch_roll_heading, 1, GroupsNamed),
+```
+
 Data format references
 ----------------------
 
diff --git a/include/x_plane_data_group_lat_lon_alt.hrl b/include/x_plane_data_group_lat_lon_alt.hrl
new file mode 100644 (file)
index 0000000..f771527
--- /dev/null
@@ -0,0 +1,10 @@
+-record(x_plane_data_group_lat_lon_alt,
+    { lat_deg   :: float() % 1
+    , lon_deg   :: float() % 2
+    , alt_ftmsl :: float() % 3
+    , alt_ftagl :: float() % 4
+    , on_runwy  :: float() % 5
+    , alt_ind   :: float() % 6
+    , lat_south :: float() % 7
+    , lon_west  :: float() % 8
+    }).
diff --git a/include/x_plane_data_group_pitch_roll_heading.hrl b/include/x_plane_data_group_pitch_roll_heading.hrl
new file mode 100644 (file)
index 0000000..d2cbe30
--- /dev/null
@@ -0,0 +1,10 @@
+-record(x_plane_data_group_pitch_roll_heading,
+    { pitch_deg  :: float()  % 1
+    , roll_deg   :: float()  % 2
+    , hding_true :: float()  % 3
+    , hding_mag  :: float()  % 4
+                             % 5
+                             % 6
+                             % 7
+                             % 8
+    }).
diff --git a/include/x_plane_data_group_speeds.hrl b/include/x_plane_data_group_speeds.hrl
new file mode 100644 (file)
index 0000000..2d58af3
--- /dev/null
@@ -0,0 +1,10 @@
+-record(x_plane_data_group_speeds,
+    { vind_kias   :: float() % 1
+    , vind_keas   :: float() % 2
+    , vtrue_ktas  :: float() % 3
+    , vtrue_ktgs  :: float() % 4
+                             % 5
+    , vind_mph    :: float() % 6
+    , vtrue_mphas :: float() % 7
+    , vtrue_mphgs :: float() % 8
+    }).
index 7ea2705..c94ed00 100644 (file)
@@ -1,6 +1,6 @@
 %%% vim: set filetype=erlang:
 { deps
-, [
+, [ {hope, ".*", {git, "https://github.com/ibnfirnas/hope.git", {tag, "3.8.1"}}}
   ]
 }.
 
index 2084322..9e16c56 100644 (file)
@@ -1,7 +1,7 @@
 {application, x_plane_data,
  [
   {description, "X-Plane UDP data packet parser."},
-  {vsn, "0.1.0"},
+  {vsn, "0.2.0"},
   {registered, []},
   {applications, [
                   kernel,
diff --git a/src/x_plane_data_group_lat_lon_alt.erl b/src/x_plane_data_group_lat_lon_alt.erl
new file mode 100644 (file)
index 0000000..ff0026a
--- /dev/null
@@ -0,0 +1,30 @@
+-module(x_plane_data_group_lat_lon_alt).
+
+-include("include/x_plane_data_group_lat_lon_alt.hrl").
+
+-export_type(
+    [ t/0
+    ]).
+
+-export(
+    [ of_raw_values_v10/1
+    ]).
+
+-define(T, #?MODULE).
+
+-type t() ::
+    ?T{}.
+
+-spec of_raw_values_v10(x_plane_data_raw:group_values()) ->
+    t().
+of_raw_values_v10({V1, V2, V3, V4, V5, V6, V7, V8}) ->
+    ?T
+    { lat_deg   = V1
+    , lon_deg   = V2
+    , alt_ftmsl = V3
+    , alt_ftagl = V4
+    , on_runwy  = V5
+    , alt_ind   = V6
+    , lat_south = V7
+    , lon_west  = V8
+    }.
diff --git a/src/x_plane_data_group_pitch_roll_heading.erl b/src/x_plane_data_group_pitch_roll_heading.erl
new file mode 100644 (file)
index 0000000..12a13ff
--- /dev/null
@@ -0,0 +1,26 @@
+-module(x_plane_data_group_pitch_roll_heading).
+
+-include("include/x_plane_data_group_pitch_roll_heading.hrl").
+
+-export_type(
+    [ t/0
+    ]).
+
+-export(
+    [ of_raw_values_v10/1
+    ]).
+
+-define(T, #?MODULE).
+
+-type t() ::
+    ?T{}.
+
+-spec of_raw_values_v10(x_plane_data_raw:group_values()) ->
+    t().
+of_raw_values_v10({V1, V2, V3, V4, _, _, _, _}) ->
+    ?T
+    { pitch_deg  = V1
+    , roll_deg   = V2
+    , hding_true = V3
+    , hding_mag  = V4
+    }.
diff --git a/src/x_plane_data_group_speeds.erl b/src/x_plane_data_group_speeds.erl
new file mode 100644 (file)
index 0000000..c8f9253
--- /dev/null
@@ -0,0 +1,30 @@
+-module(x_plane_data_group_speeds).
+
+-include("include/x_plane_data_group_speeds.hrl").
+
+-export_type(
+    [ t/0
+    ]).
+
+-export(
+    [ of_raw_values_v10/1
+    ]).
+
+-define(T, #?MODULE).
+
+-type t() ::
+    ?T{}.
+
+-spec of_raw_values_v10(x_plane_data_raw:group_values()) ->
+    t().
+of_raw_values_v10({V1, V2, V3, V4, _, V6, V7, V8}) ->
+    ?T
+    { vind_kias   = V1
+    , vind_keas   = V2
+    , vtrue_ktas  = V3
+    , vtrue_ktgs  = V4
+
+    , vind_mph    = V6
+    , vtrue_mphas = V7
+    , vtrue_mphgs = V8
+    }.
diff --git a/src/x_plane_data_named.erl b/src/x_plane_data_named.erl
new file mode 100644 (file)
index 0000000..250bf80
--- /dev/null
@@ -0,0 +1,55 @@
+-module(x_plane_data_named).
+
+-export_type(
+    [ t/0
+    , version/0
+    , group/0
+    ]).
+
+-export(
+    [ of_raw/1
+    ]).
+
+-type version() ::
+    x_plane_data_v10.
+
+-type group() ::
+      {speeds            , x_plane_data_group_speeds:t()}
+    | {pitch_roll_heading, x_plane_data_group_pitch_roll_heading:t()}
+    | {lat_lon_alt       , x_plane_data_group_lat_lon_alt:t()}
+    .
+
+-type t() ::
+    {version(), [group()]}.
+
+-define(DATA_INDEX_V10, 64).
+
+-spec of_raw(x_plane_data_raw:t()) ->
+    hope_result:t(t(), unknown_x_plane_version).
+of_raw({?DATA_INDEX_V10, GroupsRaw}) ->
+    ConsKnownDropUnknown =
+        fun (GroupRaw, Groups1) ->
+            GroupOpt = v10_group_identify(GroupRaw),
+            Groups2Opt = hope_option:map(GroupOpt, fun (G) -> [G | Groups1] end),
+            hope_option:get(Groups2Opt, Groups1)
+        end,
+    GroupsNamed = lists:foldl(ConsKnownDropUnknown, [], GroupsRaw),
+    T = {x_plane_data_v10, GroupsNamed},
+    {ok, T};
+of_raw({_, _}) ->
+    {error, unknown_x_plane_version}.
+
+-spec v10_group_identify(x_plane_data_raw:group()) ->
+    hope_option:t(group()).
+v10_group_identify({Index, Values}) ->
+    LabAndConsOpt = v10_index_to_label_and_constructor(Index),
+    hope_option:map(LabAndConsOpt, fun ({L, C}) -> {L, C(Values)} end).
+
+v10_index_to_label_and_constructor(Index) ->
+    F = of_raw_values_v10,
+    case Index
+    of  3  -> {some, {speeds            , fun x_plane_data_group_speeds:F/1}}
+    ;   17 -> {some, {pitch_roll_heading, fun x_plane_data_group_pitch_roll_heading:F/1}}
+    ;   20 -> {some, {lat_lon_alt       , fun x_plane_data_group_lat_lon_alt:F/1}}
+    ;   _ -> none
+    end.
index 253e286..3729601 100644 (file)
@@ -1,5 +1,9 @@
 -module(x_plane_data_SUITE).
 
+-include_lib("x_plane_data_group_lat_lon_alt.hrl").
+-include_lib("x_plane_data_group_pitch_roll_heading.hrl").
+-include_lib("x_plane_data_group_speeds.hrl").
+
 %% CT callbacks
 -export(
     [ all/0
@@ -8,7 +12,8 @@
 
 %% Test cases
 -export(
-    [ t_basic_sanity_check/1
+    [ t_bin_to_raw/1
+    , t_bin_to_raw_to_named/1
     ]).
 
 -define(GROUP, x_plane_data).
@@ -23,7 +28,8 @@ all() ->
 
 groups() ->
     Tests =
-        [ t_basic_sanity_check
+        [ t_bin_to_raw
+        , t_bin_to_raw_to_named
         ],
     Properties = [parallel],
     [ {?GROUP, Properties, Tests}
@@ -34,7 +40,7 @@ groups() ->
 %%  Test cases
 %% =============================================================================
 
-t_basic_sanity_check(_Cfg) ->
+t_bin_to_raw(_Cfg) ->
     Test =
         fun (PacketBase64) ->
             Packet = base64:decode(PacketBase64),
@@ -80,6 +86,48 @@ t_basic_sanity_check(_Cfg) ->
         end,
     lists:foreach(Test, sample_packets_base64_encoded()).
 
+t_bin_to_raw_to_named(_Cfg) ->
+    Test =
+        fun (PacketBase64) ->
+            Packet = base64:decode(PacketBase64),
+            {ok, DataRaw} = x_plane_data_raw:of_bin(Packet),
+            ct:log("DataRaw: ~p", [DataRaw]),
+            {64, _} = DataRaw,
+            {ok, DataNamed} = x_plane_data_named:of_raw(DataRaw),
+            ct:log("DataNamed: ~p", [DataNamed]),
+            {x_plane_data_v10, Groups} = DataNamed,
+            {some, #x_plane_data_group_speeds
+                { vind_kias   = 3.106105089187622
+                , vind_keas   = 6.640225887298584
+                , vtrue_ktas  = 6.793502330780029
+                , vtrue_ktgs  = 1.0040892448159866e-5
+                , vind_mph    = 3.574441909790039
+                , vtrue_mphas = 7.81782341003418
+                , vtrue_mphgs = 1.1554855518625118e-5
+                }
+            } = kv_list_find(Groups, speeds),
+            {some, #x_plane_data_group_pitch_roll_heading
+                { pitch_deg  = 2.3310465812683105
+                , roll_deg   = 0.22457626461982727
+                , hding_true = 120.6203384399414
+                , hding_mag  = 133.51084899902344
+                }
+            } = kv_list_find(Groups, pitch_roll_heading),
+            {some, #x_plane_data_group_lat_lon_alt
+                { lat_deg   = 40.64827346801758
+                , lon_deg   = -73.81651306152344
+                , alt_ftmsl = 7.969515800476074
+                , alt_ftagl = 0.226793110370636
+                , on_runwy  = 1.0
+                , alt_ind   = -70.99662780761719
+                , lat_south = 40.0
+                , lon_west  = -75.0
+                }
+            } = kv_list_find(Groups, lat_lon_alt),
+            ok
+        end,
+    lists:foreach(Test, sample_packets_base64_encoded()).
+
 %% =============================================================================
 %% Sample data
 %% =============================================================================
This page took 0.029536 seconds and 4 git commands to generate.