From 84fa8ccb7143428a0aa49ceeb632ff45b374d8b8 Mon Sep 17 00:00:00 2001 From: Siraaj Khandkar Date: Mon, 5 Oct 2015 05:57:14 -0400 Subject: [PATCH] Implement named data groups. --- README.md | 58 ++++++++++++++++++- include/x_plane_data_group_lat_lon_alt.hrl | 10 ++++ .../x_plane_data_group_pitch_roll_heading.hrl | 10 ++++ include/x_plane_data_group_speeds.hrl | 10 ++++ rebar.config | 2 +- src/x_plane_data.app.src | 2 +- src/x_plane_data_group_lat_lon_alt.erl | 30 ++++++++++ src/x_plane_data_group_pitch_roll_heading.erl | 26 +++++++++ src/x_plane_data_group_speeds.erl | 30 ++++++++++ src/x_plane_data_named.erl | 55 ++++++++++++++++++ test/x_plane_data_SUITE.erl | 54 ++++++++++++++++- 11 files changed, 279 insertions(+), 8 deletions(-) create mode 100644 include/x_plane_data_group_lat_lon_alt.hrl create mode 100644 include/x_plane_data_group_pitch_roll_heading.hrl create mode 100644 include/x_plane_data_group_speeds.hrl create mode 100644 src/x_plane_data_group_lat_lon_alt.erl create mode 100644 src/x_plane_data_group_pitch_roll_heading.erl create mode 100644 src/x_plane_data_group_speeds.erl create mode 100644 src/x_plane_data_named.erl diff --git a/README.md b/README.md index 2de6895..b417370 100644 --- 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 index 0000000..f771527 --- /dev/null +++ b/include/x_plane_data_group_lat_lon_alt.hrl @@ -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 index 0000000..d2cbe30 --- /dev/null +++ b/include/x_plane_data_group_pitch_roll_heading.hrl @@ -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 index 0000000..2d58af3 --- /dev/null +++ b/include/x_plane_data_group_speeds.hrl @@ -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 + }). diff --git a/rebar.config b/rebar.config index 7ea2705..c94ed00 100644 --- a/rebar.config +++ b/rebar.config @@ -1,6 +1,6 @@ %%% vim: set filetype=erlang: { deps -, [ +, [ {hope, ".*", {git, "https://github.com/ibnfirnas/hope.git", {tag, "3.8.1"}}} ] }. diff --git a/src/x_plane_data.app.src b/src/x_plane_data.app.src index 2084322..9e16c56 100644 --- a/src/x_plane_data.app.src +++ b/src/x_plane_data.app.src @@ -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 index 0000000..ff0026a --- /dev/null +++ b/src/x_plane_data_group_lat_lon_alt.erl @@ -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 index 0000000..12a13ff --- /dev/null +++ b/src/x_plane_data_group_pitch_roll_heading.erl @@ -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 index 0000000..c8f9253 --- /dev/null +++ b/src/x_plane_data_group_speeds.erl @@ -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 index 0000000..250bf80 --- /dev/null +++ b/src/x_plane_data_named.erl @@ -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. diff --git a/test/x_plane_data_SUITE.erl b/test/x_plane_data_SUITE.erl index 253e286..3729601 100644 --- a/test/x_plane_data_SUITE.erl +++ b/test/x_plane_data_SUITE.erl @@ -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 %% ============================================================================= -- 2.20.1