test(gw_jt808): frame parser and channel SUITE
This commit is contained in:
parent
4d493292fb
commit
dc64068e41
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,100 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2023 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqx_jt808_auth_http_test_server).
|
||||
|
||||
-behaviour(supervisor).
|
||||
-behaviour(cowboy_handler).
|
||||
|
||||
% cowboy_server callbacks
|
||||
-export([init/2]).
|
||||
|
||||
% supervisor callbacks
|
||||
-export([init/1]).
|
||||
|
||||
% API
|
||||
-export([
|
||||
start_link/0, start_link/1, start_link/2,
|
||||
stop/0,
|
||||
set_handler/1
|
||||
]).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% API
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
start_link() ->
|
||||
start_link(8991).
|
||||
|
||||
start_link(Port) ->
|
||||
start_link(Port, "/[...]").
|
||||
|
||||
start_link(Port, Path) ->
|
||||
supervisor:start_link({local, ?MODULE}, ?MODULE, [Port, Path]).
|
||||
|
||||
stop() ->
|
||||
gen_server:stop(?MODULE).
|
||||
|
||||
set_handler(F) when is_function(F, 2) ->
|
||||
true = ets:insert(?MODULE, {handler, F}),
|
||||
ok.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% supervisor API
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
init([Port, Path]) ->
|
||||
Dispatch = cowboy_router:compile(
|
||||
[
|
||||
{'_', [{Path, ?MODULE, []}]}
|
||||
]
|
||||
),
|
||||
TransOpts = #{
|
||||
socket_opts => [{port, Port}],
|
||||
connection_type => supervisor
|
||||
},
|
||||
ProtoOpts = #{env => #{dispatch => Dispatch}},
|
||||
|
||||
Tab = ets:new(?MODULE, [set, named_table, public]),
|
||||
ets:insert(Tab, {handler, fun default_handler/2}),
|
||||
|
||||
ChildSpec = ranch:child_spec(?MODULE, ranch_tcp, TransOpts, cowboy_clear, ProtoOpts),
|
||||
{ok, {{one_for_one, 10, 10}, [ChildSpec]}}.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% cowboy_server API
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
init(Req, State) ->
|
||||
[{handler, Handler}] = ets:lookup(?MODULE, handler),
|
||||
Handler(Req, State).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
default_handler(Req0 = #{method := <<"POST">>, path := <<"/jt808/registry">>}, State) ->
|
||||
Req = cowboy_req:reply(
|
||||
200,
|
||||
#{<<"content-type">> => <<"application/json">>},
|
||||
emqx_utils_json:encode(#{code => 0, authcode => <<"123456">>}),
|
||||
Req0
|
||||
),
|
||||
{ok, Req, State};
|
||||
default_handler(Req0 = #{method := <<"POST">>, path := <<"/jt808/auth">>}, State) ->
|
||||
Req = cowboy_req:reply(
|
||||
200,
|
||||
#{<<"content-type">> => <<"application/json">>},
|
||||
emqx_utils_json:encode(#{client_id => <<"abcdef">>}),
|
||||
Req0
|
||||
),
|
||||
{ok, Req, State};
|
||||
default_handler(Req0, State) ->
|
||||
Req = cowboy_req:reply(
|
||||
400,
|
||||
#{<<"content-type">> => <<"text/plain">>},
|
||||
<<"">>,
|
||||
Req0
|
||||
),
|
||||
{ok, Req, State}.
|
|
@ -0,0 +1,721 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2023 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqx_jt808_parser_SUITE).
|
||||
|
||||
-compile(export_all).
|
||||
-compile(nowarn_export_all).
|
||||
|
||||
-include("emqx_jt808.hrl").
|
||||
|
||||
-define(LOGT(Format, Args), ct:print("TEST_SUITE: " ++ Format, Args)).
|
||||
|
||||
-define(FRM_FLAG, 16#7e:8).
|
||||
-define(RESERVE, 0).
|
||||
-define(NO_FRAGMENT, 0).
|
||||
-define(WITH_FRAGMENT, 1).
|
||||
-define(NO_ENCRYPT, 0).
|
||||
-define(MSG_SIZE(X), X:10 / big - integer).
|
||||
|
||||
-define(word, 16 / big - integer).
|
||||
-define(dword, 32 / big - integer).
|
||||
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
all() ->
|
||||
emqx_common_test_helpers:all(?MODULE).
|
||||
|
||||
init_per_suite(Config) ->
|
||||
Config.
|
||||
|
||||
end_per_suite(Config) ->
|
||||
Config.
|
||||
|
||||
t_case01_register(_Config) ->
|
||||
Parser = emqx_jt808_frame:initial_parse_state(#{}),
|
||||
Manuf = <<"examp">>,
|
||||
Model = <<"33333333333333333333">>,
|
||||
DevId = <<"1234567">>,
|
||||
Color = 3,
|
||||
Plate = <<"ujvl239">>,
|
||||
RegisterPacket =
|
||||
<<58:?word, 59:?word, Manuf/binary, Model/binary, DevId/binary, Color, Plate/binary>>,
|
||||
MsgId = 16#0100,
|
||||
PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>,
|
||||
MsgSn = 78,
|
||||
Size = size(RegisterPacket),
|
||||
Header =
|
||||
<<MsgId:?word, ?RESERVE:2, ?NO_FRAGMENT:1, ?NO_ENCRYPT:3, ?MSG_SIZE(Size), PhoneBCD/binary,
|
||||
MsgSn:?word>>,
|
||||
Stream = encode(Header, RegisterPacket),
|
||||
|
||||
{ok, Map, Rest, State} = emqx_jt808_frame:parse(Stream, Parser),
|
||||
?assertEqual(
|
||||
#{
|
||||
<<"header">> => #{
|
||||
<<"msg_id">> => MsgId,
|
||||
<<"encrypt">> => ?NO_ENCRYPT,
|
||||
<<"phone">> => <<"000123456789">>,
|
||||
<<"len">> => Size,
|
||||
<<"msg_sn">> => MsgSn
|
||||
},
|
||||
<<"body">> => #{
|
||||
<<"province">> => 58,
|
||||
<<"city">> => 59,
|
||||
<<"manufacturer">> => Manuf,
|
||||
<<"model">> => Model,
|
||||
<<"dev_id">> => DevId,
|
||||
<<"color">> => Color,
|
||||
<<"license_number">> => Plate
|
||||
}
|
||||
},
|
||||
Map
|
||||
),
|
||||
?assertEqual(<<>>, Rest),
|
||||
?assertEqual(#{data => <<>>, phase => searching_head_hex7e}, State),
|
||||
ok.
|
||||
|
||||
t_case02_register_ack(_Config) ->
|
||||
% register ack
|
||||
MsgId = 16#8100,
|
||||
MsgSn = 35,
|
||||
Seq = 22,
|
||||
Result = 1,
|
||||
Code = <<"abcdef">>,
|
||||
DownlinkJson = #{
|
||||
<<"header">> => #{
|
||||
<<"msg_id">> => MsgId,
|
||||
<<"encrypt">> => ?NO_ENCRYPT,
|
||||
<<"phone">> => <<"000123456789">>,
|
||||
<<"msg_sn">> => MsgSn
|
||||
},
|
||||
<<"body">> => #{<<"seq">> => Seq, <<"result">> => Result, <<"auth_code">> => Code}
|
||||
},
|
||||
Stream = emqx_jt808_frame:serialize_pkt(DownlinkJson, #{}),
|
||||
|
||||
RegisterAckPacket = <<Seq:?word, Result:8, Code/binary>>,
|
||||
|
||||
PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>,
|
||||
|
||||
Size = size(RegisterAckPacket),
|
||||
Header =
|
||||
<<MsgId:?word, ?RESERVE:2, ?NO_FRAGMENT:1, ?NO_ENCRYPT:3, ?MSG_SIZE(Size), PhoneBCD/binary,
|
||||
MsgSn:?word>>,
|
||||
StreamByHand = encode(Header, RegisterAckPacket),
|
||||
|
||||
?assertEqual(StreamByHand, Stream),
|
||||
ok.
|
||||
|
||||
t_case04_MC_LOCATION_REPORT(_Config) ->
|
||||
Parser = emqx_jt808_frame:initial_parse_state(#{}),
|
||||
Data =
|
||||
<<126, 2, 0, 0, 60, 1, 136, 118, 99, 137, 114, 0, 229, 0, 0, 0, 0, 0, 4, 0, 0, 1, 49, 122,
|
||||
103, 6, 147, 104, 81, 0, 14, 0, 0, 0, 39, 23, 16, 25, 25, 53, 56, 1, 4, 0, 0, 63, 178,
|
||||
3, 2, 0, 0, 37, 4, 0, 0, 0, 0, 42, 2, 0, 0, 43, 4, 0, 0, 0, 0, 48, 1, 31, 49, 1, 0, 171,
|
||||
126>>,
|
||||
{ok, Map, Rest, State} = emqx_jt808_frame:parse(Data, Parser),
|
||||
?assertEqual(
|
||||
#{
|
||||
<<"header">> =>
|
||||
#{
|
||||
<<"encrypt">> => 0,
|
||||
<<"len">> => 60,
|
||||
<<"msg_id">> => 512,
|
||||
<<"msg_sn">> => 229,
|
||||
<<"phone">> => <<"018876638972">>
|
||||
},
|
||||
<<"body">> =>
|
||||
#{
|
||||
<<"alarm">> => 0,
|
||||
<<"altitude">> => 14,
|
||||
<<"direction">> => 39,
|
||||
<<"extra">> =>
|
||||
#{
|
||||
<<"analog">> => #{<<"ad0">> => 0, <<"ad1">> => 0},
|
||||
<<"gnss_sat_num">> => 0,
|
||||
<<"io_status">> => #{<<"deep_sleep">> => 0, <<"sleep">> => 0},
|
||||
<<"mileage">> => 16306,
|
||||
<<"rssi">> => 31,
|
||||
<<"signal">> =>
|
||||
#{
|
||||
<<"abs">> => 0,
|
||||
<<"air_conditioner">> => 0,
|
||||
<<"brake">> => 0,
|
||||
<<"cluth">> => 0,
|
||||
<<"fog">> => 0,
|
||||
<<"heater">> => 0,
|
||||
<<"high_beam">> => 0,
|
||||
<<"horn">> => 0,
|
||||
<<"left_turn">> => 0,
|
||||
<<"low_beam">> => 0,
|
||||
<<"neutral">> => 0,
|
||||
<<"retarder">> => 0,
|
||||
<<"reverse">> => 0,
|
||||
<<"right_turn">> => 0,
|
||||
<<"side_marker">> => 0
|
||||
},
|
||||
<<"speed">> => 0
|
||||
},
|
||||
<<"latitude">> => 20019815,
|
||||
<<"longitude">> => 110323793,
|
||||
<<"speed">> => 0,
|
||||
<<"status">> => 262144,
|
||||
<<"time">> => <<"171019193538">>
|
||||
}
|
||||
},
|
||||
Map
|
||||
),
|
||||
?assertEqual(<<>>, Rest),
|
||||
?assertEqual(#{data => <<>>, phase => searching_head_hex7e}, State),
|
||||
ok.
|
||||
|
||||
t_case05_MC_BULK_LOCATION_REPORT(_Config) ->
|
||||
Parser = emqx_jt808_frame:initial_parse_state(#{}),
|
||||
Data =
|
||||
<<126, 7, 4, 1, 57, 1, 136, 118, 99, 137, 114, 0, 231, 0, 5, 1, 0, 60, 0, 0, 0, 0, 0, 4, 0,
|
||||
3, 1, 49, 115, 43, 6, 145, 211, 81, 0, 31, 0, 166, 0, 171, 23, 8, 49, 16, 73, 51, 1, 4,
|
||||
0, 0, 60, 85, 3, 2, 0, 0, 37, 4, 0, 0, 0, 0, 42, 2, 0, 0, 43, 4, 0, 0, 0, 0, 48, 1, 0,
|
||||
49, 1, 12, 0, 60, 0, 0, 0, 0, 0, 4, 0, 3, 1, 49, 114, 74, 6, 145, 212, 2, 0, 29, 0, 222,
|
||||
0, 125, 2, 23, 8, 49, 16, 73, 56, 1, 4, 0, 0, 60, 85, 3, 2, 0, 0, 37, 4, 0, 0, 0, 0, 42,
|
||||
2, 0, 0, 43, 4, 0, 0, 0, 0, 48, 1, 0, 49, 1, 12, 0, 60, 0, 0, 0, 0, 0, 4, 0, 3, 1, 49,
|
||||
109, 222, 6, 145, 225, 80, 0, 37, 1, 169, 0, 109, 23, 8, 49, 16, 80, 17, 1, 4, 0, 0, 60,
|
||||
89, 3, 2, 0, 0, 37, 4, 0, 0, 0, 0, 42, 2, 0, 0, 43, 4, 0, 0, 0, 0, 48, 1, 0, 49, 1, 12,
|
||||
0, 60, 0, 0, 0, 0, 0, 4, 0, 3, 1, 49, 90, 235, 6, 146, 0, 24, 0, 43, 2, 136, 0, 114, 23,
|
||||
8, 49, 16, 81, 17, 1, 4, 0, 0, 60, 99, 3, 2, 0, 0, 37, 4, 0, 0, 0, 0, 42, 2, 0, 0, 43,
|
||||
4, 0, 0, 0, 0, 48, 1, 0, 49, 1, 12, 0, 60, 0, 0, 0, 0, 0, 4, 0, 3, 1, 49, 91, 120, 6,
|
||||
146, 43, 21, 0, 43, 2, 247, 0, 83, 23, 8, 49, 16, 82, 20, 1, 4, 0, 0, 60, 111, 3, 2, 0,
|
||||
0, 37, 4, 0, 0, 0, 0, 42, 2, 0, 0, 43, 4, 0, 0, 0, 0, 48, 1, 0, 49, 1, 12, 132, 126>>,
|
||||
{ok, Map, Rest, State} = emqx_jt808_frame:parse(Data, Parser),
|
||||
?assertEqual(
|
||||
#{
|
||||
<<"body">> =>
|
||||
#{
|
||||
<<"length">> => 5,
|
||||
<<"location">> =>
|
||||
[
|
||||
#{
|
||||
<<"alarm">> => 0,
|
||||
<<"altitude">> => 31,
|
||||
<<"direction">> => 171,
|
||||
<<"extra">> =>
|
||||
#{
|
||||
<<"analog">> =>
|
||||
#{
|
||||
<<"ad0">> => 0,
|
||||
<<"ad1">> => 0
|
||||
},
|
||||
<<"gnss_sat_num">> => 12,
|
||||
<<"io_status">> =>
|
||||
#{
|
||||
<<"deep_sleep">> => 0,
|
||||
<<"sleep">> => 0
|
||||
},
|
||||
<<"mileage">> => 15445,
|
||||
<<"rssi">> => 0,
|
||||
<<"signal">> =>
|
||||
#{
|
||||
<<"abs">> => 0,
|
||||
<<"air_conditioner">> =>
|
||||
0,
|
||||
<<"brake">> => 0,
|
||||
<<"cluth">> => 0,
|
||||
<<"fog">> => 0,
|
||||
<<"heater">> => 0,
|
||||
<<"high_beam">> => 0,
|
||||
<<"horn">> => 0,
|
||||
<<"left_turn">> => 0,
|
||||
<<"low_beam">> => 0,
|
||||
<<"neutral">> => 0,
|
||||
<<"retarder">> => 0,
|
||||
<<"reverse">> => 0,
|
||||
<<"right_turn">> => 0,
|
||||
<<"side_marker">> => 0
|
||||
},
|
||||
<<"speed">> => 0
|
||||
},
|
||||
<<"latitude">> => 20017963,
|
||||
<<"longitude">> => 110220113,
|
||||
<<"speed">> => 166,
|
||||
<<"status">> => 262147,
|
||||
<<"time">> => <<"170831104933">>
|
||||
},
|
||||
#{
|
||||
<<"alarm">> => 0,
|
||||
<<"altitude">> => 29,
|
||||
<<"direction">> => 126,
|
||||
<<"extra">> =>
|
||||
#{
|
||||
<<"analog">> =>
|
||||
#{
|
||||
<<"ad0">> => 0,
|
||||
<<"ad1">> => 0
|
||||
},
|
||||
<<"gnss_sat_num">> => 12,
|
||||
<<"io_status">> =>
|
||||
#{
|
||||
<<"deep_sleep">> => 0,
|
||||
<<"sleep">> => 0
|
||||
},
|
||||
<<"mileage">> => 15445,
|
||||
<<"rssi">> => 0,
|
||||
<<"signal">> =>
|
||||
#{
|
||||
<<"abs">> => 0,
|
||||
<<"air_conditioner">> =>
|
||||
0,
|
||||
<<"brake">> => 0,
|
||||
<<"cluth">> => 0,
|
||||
<<"fog">> => 0,
|
||||
<<"heater">> => 0,
|
||||
<<"high_beam">> => 0,
|
||||
<<"horn">> => 0,
|
||||
<<"left_turn">> => 0,
|
||||
<<"low_beam">> => 0,
|
||||
<<"neutral">> => 0,
|
||||
<<"retarder">> => 0,
|
||||
<<"reverse">> => 0,
|
||||
<<"right_turn">> => 0,
|
||||
<<"side_marker">> => 0
|
||||
},
|
||||
<<"speed">> => 0
|
||||
},
|
||||
<<"latitude">> => 20017738,
|
||||
<<"longitude">> => 110220290,
|
||||
<<"speed">> => 222,
|
||||
<<"status">> => 262147,
|
||||
<<"time">> => <<"170831104938">>
|
||||
},
|
||||
#{
|
||||
<<"alarm">> => 0,
|
||||
<<"altitude">> => 37,
|
||||
<<"direction">> => 109,
|
||||
<<"extra">> =>
|
||||
#{
|
||||
<<"analog">> =>
|
||||
#{
|
||||
<<"ad0">> => 0,
|
||||
<<"ad1">> => 0
|
||||
},
|
||||
<<"gnss_sat_num">> => 12,
|
||||
<<"io_status">> =>
|
||||
#{
|
||||
<<"deep_sleep">> => 0,
|
||||
<<"sleep">> => 0
|
||||
},
|
||||
<<"mileage">> => 15449,
|
||||
<<"rssi">> => 0,
|
||||
<<"signal">> =>
|
||||
#{
|
||||
<<"abs">> => 0,
|
||||
<<"air_conditioner">> =>
|
||||
0,
|
||||
<<"brake">> => 0,
|
||||
<<"cluth">> => 0,
|
||||
<<"fog">> => 0,
|
||||
<<"heater">> => 0,
|
||||
<<"high_beam">> => 0,
|
||||
<<"horn">> => 0,
|
||||
<<"left_turn">> => 0,
|
||||
<<"low_beam">> => 0,
|
||||
<<"neutral">> => 0,
|
||||
<<"retarder">> => 0,
|
||||
<<"reverse">> => 0,
|
||||
<<"right_turn">> => 0,
|
||||
<<"side_marker">> => 0
|
||||
},
|
||||
<<"speed">> => 0
|
||||
},
|
||||
<<"latitude">> => 20016606,
|
||||
<<"longitude">> => 110223696,
|
||||
<<"speed">> => 425,
|
||||
<<"status">> => 262147,
|
||||
<<"time">> => <<"170831105011">>
|
||||
},
|
||||
#{
|
||||
<<"alarm">> => 0,
|
||||
<<"altitude">> => 43,
|
||||
<<"direction">> => 114,
|
||||
<<"extra">> =>
|
||||
#{
|
||||
<<"analog">> =>
|
||||
#{
|
||||
<<"ad0">> => 0,
|
||||
<<"ad1">> => 0
|
||||
},
|
||||
<<"gnss_sat_num">> => 12,
|
||||
<<"io_status">> =>
|
||||
#{
|
||||
<<"deep_sleep">> => 0,
|
||||
<<"sleep">> => 0
|
||||
},
|
||||
<<"mileage">> => 15459,
|
||||
<<"rssi">> => 0,
|
||||
<<"signal">> =>
|
||||
#{
|
||||
<<"abs">> => 0,
|
||||
<<"air_conditioner">> =>
|
||||
0,
|
||||
<<"brake">> => 0,
|
||||
<<"cluth">> => 0,
|
||||
<<"fog">> => 0,
|
||||
<<"heater">> => 0,
|
||||
<<"high_beam">> => 0,
|
||||
<<"horn">> => 0,
|
||||
<<"left_turn">> => 0,
|
||||
<<"low_beam">> => 0,
|
||||
<<"neutral">> => 0,
|
||||
<<"retarder">> => 0,
|
||||
<<"reverse">> => 0,
|
||||
<<"right_turn">> => 0,
|
||||
<<"side_marker">> => 0
|
||||
},
|
||||
<<"speed">> => 0
|
||||
},
|
||||
<<"latitude">> => 20011755,
|
||||
<<"longitude">> => 110231576,
|
||||
<<"speed">> => 648,
|
||||
<<"status">> => 262147,
|
||||
<<"time">> => <<"170831105111">>
|
||||
},
|
||||
#{
|
||||
<<"alarm">> => 0,
|
||||
<<"altitude">> => 43,
|
||||
<<"direction">> => 83,
|
||||
<<"extra">> =>
|
||||
#{
|
||||
<<"analog">> =>
|
||||
#{
|
||||
<<"ad0">> => 0,
|
||||
<<"ad1">> => 0
|
||||
},
|
||||
<<"gnss_sat_num">> => 12,
|
||||
<<"io_status">> =>
|
||||
#{
|
||||
<<"deep_sleep">> => 0,
|
||||
<<"sleep">> => 0
|
||||
},
|
||||
<<"mileage">> => 15471,
|
||||
<<"rssi">> => 0,
|
||||
<<"signal">> =>
|
||||
#{
|
||||
<<"abs">> => 0,
|
||||
<<"air_conditioner">> =>
|
||||
0,
|
||||
<<"brake">> => 0,
|
||||
<<"cluth">> => 0,
|
||||
<<"fog">> => 0,
|
||||
<<"heater">> => 0,
|
||||
<<"high_beam">> => 0,
|
||||
<<"horn">> => 0,
|
||||
<<"left_turn">> => 0,
|
||||
<<"low_beam">> => 0,
|
||||
<<"neutral">> => 0,
|
||||
<<"retarder">> => 0,
|
||||
<<"reverse">> => 0,
|
||||
<<"right_turn">> => 0,
|
||||
<<"side_marker">> => 0
|
||||
},
|
||||
<<"speed">> => 0
|
||||
},
|
||||
<<"latitude">> => 20011896,
|
||||
<<"longitude">> => 110242581,
|
||||
<<"speed">> => 759,
|
||||
<<"status">> => 262147,
|
||||
<<"time">> => <<"170831105214">>
|
||||
}
|
||||
],
|
||||
<<"type">> => 1
|
||||
},
|
||||
<<"header">> =>
|
||||
#{
|
||||
<<"encrypt">> => 0,
|
||||
<<"len">> => 313,
|
||||
<<"msg_id">> => 1796,
|
||||
<<"msg_sn">> => 231,
|
||||
<<"phone">> => <<"018876638972">>
|
||||
}
|
||||
},
|
||||
Map
|
||||
),
|
||||
?assertEqual(<<>>, Rest),
|
||||
?assertEqual(#{data => <<>>, phase => searching_head_hex7e}, State),
|
||||
ok.
|
||||
|
||||
t_case10_segmented_packet(_Config) ->
|
||||
Parser = emqx_jt808_frame:initial_parse_state(#{}),
|
||||
Manuf = <<"examp">>,
|
||||
Model = <<"33333333333333333333">>,
|
||||
DevId = <<"1234567">>,
|
||||
Color = 3,
|
||||
Plate = <<"ujvl239">>,
|
||||
RegisterPacket =
|
||||
<<58:?word, 59:?word, Manuf/binary, Model/binary, DevId/binary, Color, Plate/binary>>,
|
||||
MsgId = 16#0100,
|
||||
PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>,
|
||||
MsgSn = 78,
|
||||
Size = size(RegisterPacket),
|
||||
Header =
|
||||
<<MsgId:?word, ?RESERVE:2, ?NO_FRAGMENT:1, ?NO_ENCRYPT:3, ?MSG_SIZE(Size), PhoneBCD/binary,
|
||||
MsgSn:?word>>,
|
||||
Stream = encode(Header, RegisterPacket),
|
||||
|
||||
<<Part1:7/binary, Part2/binary>> = Stream,
|
||||
{more, Parser2} = emqx_jt808_frame:parse(Part1, Parser),
|
||||
?assertMatch(#{phase := escaping_hex7d}, Parser2),
|
||||
{ok, Map, Rest, State} = emqx_jt808_frame:parse(Part2, Parser2),
|
||||
?assertEqual(
|
||||
#{
|
||||
<<"header">> => #{
|
||||
<<"msg_id">> => MsgId,
|
||||
<<"encrypt">> => ?NO_ENCRYPT,
|
||||
<<"phone">> => <<"000123456789">>,
|
||||
<<"len">> => Size,
|
||||
<<"msg_sn">> => MsgSn
|
||||
},
|
||||
<<"body">> => #{
|
||||
<<"province">> => 58,
|
||||
<<"city">> => 59,
|
||||
<<"manufacturer">> => Manuf,
|
||||
<<"model">> => Model,
|
||||
<<"dev_id">> => DevId,
|
||||
<<"color">> => Color,
|
||||
<<"license_number">> => Plate
|
||||
}
|
||||
},
|
||||
Map
|
||||
),
|
||||
?assertEqual(<<>>, Rest),
|
||||
?assertEqual(#{data => <<>>, phase => searching_head_hex7e}, State),
|
||||
ok.
|
||||
|
||||
t_case11_prefix_register(_Config) ->
|
||||
Parser = emqx_jt808_frame:initial_parse_state(#{}),
|
||||
Manuf = <<"examp">>,
|
||||
Model = <<"33333333333333333333">>,
|
||||
DevId = <<"1234567">>,
|
||||
Color = 3,
|
||||
Plate = <<"ujvl239">>,
|
||||
RegisterPacket =
|
||||
<<58:?word, 59:?word, Manuf/binary, Model/binary, DevId/binary, Color, Plate/binary>>,
|
||||
MsgId = 16#0100,
|
||||
PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>,
|
||||
MsgSn = 78,
|
||||
Size = size(RegisterPacket),
|
||||
Header =
|
||||
<<MsgId:?word, ?RESERVE:2, ?NO_FRAGMENT:1, ?NO_ENCRYPT:3, ?MSG_SIZE(Size), PhoneBCD/binary,
|
||||
MsgSn:?word>>,
|
||||
Stream = encode(Header, RegisterPacket),
|
||||
MessBinary = <<0, 1, 2, 3, Stream/binary>>,
|
||||
?LOGT("MessBinary=~p", [binary_to_hex_string(MessBinary)]),
|
||||
|
||||
{ok, Map, Rest, State} = emqx_jt808_frame:parse(MessBinary, Parser),
|
||||
?assertEqual(
|
||||
#{
|
||||
<<"header">> => #{
|
||||
<<"msg_id">> => MsgId,
|
||||
<<"encrypt">> => ?NO_ENCRYPT,
|
||||
<<"phone">> => <<"000123456789">>,
|
||||
<<"len">> => Size,
|
||||
<<"msg_sn">> => MsgSn
|
||||
},
|
||||
<<"body">> => #{
|
||||
<<"province">> => 58,
|
||||
<<"city">> => 59,
|
||||
<<"manufacturer">> => Manuf,
|
||||
<<"model">> => Model,
|
||||
<<"dev_id">> => DevId,
|
||||
<<"color">> => Color,
|
||||
<<"license_number">> => Plate
|
||||
}
|
||||
},
|
||||
Map
|
||||
),
|
||||
?assertEqual(<<>>, Rest),
|
||||
?assertEqual(#{data => <<>>, phase => searching_head_hex7e}, State),
|
||||
ok.
|
||||
|
||||
t_case12_0x7e_in_message(_Config) ->
|
||||
Parser = emqx_jt808_frame:initial_parse_state(#{}),
|
||||
Manuf = <<"examp">>,
|
||||
Model = <<"33333333333333333333">>,
|
||||
DevId = <<"1234567">>,
|
||||
Color = 3,
|
||||
Plate = <<"ujvl239">>,
|
||||
% pay attention to this
|
||||
AlarmInt = 16#7e,
|
||||
AlarmDigit = 16#7d,
|
||||
RegisterPacket =
|
||||
<<AlarmInt:?word, AlarmDigit:?word, Manuf/binary, Model/binary, DevId/binary, Color,
|
||||
Plate/binary>>,
|
||||
MsgId = 16#0100,
|
||||
PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>,
|
||||
MsgSn = 78,
|
||||
Size = size(RegisterPacket),
|
||||
Header =
|
||||
<<MsgId:?word, ?RESERVE:2, ?NO_FRAGMENT:1, ?NO_ENCRYPT:3, ?MSG_SIZE(Size), PhoneBCD/binary,
|
||||
MsgSn:?word>>,
|
||||
Stream = encode(Header, RegisterPacket),
|
||||
|
||||
{ok, Map, Rest, State} = emqx_jt808_frame:parse(Stream, Parser),
|
||||
?assertEqual(
|
||||
#{
|
||||
<<"header">> => #{
|
||||
<<"msg_id">> => MsgId,
|
||||
<<"encrypt">> => ?NO_ENCRYPT,
|
||||
<<"phone">> => <<"000123456789">>,
|
||||
<<"len">> => Size,
|
||||
<<"msg_sn">> => MsgSn
|
||||
},
|
||||
<<"body">> => #{
|
||||
<<"province">> => AlarmInt,
|
||||
<<"city">> => AlarmDigit,
|
||||
<<"manufacturer">> => Manuf,
|
||||
<<"model">> => Model,
|
||||
<<"dev_id">> => DevId,
|
||||
<<"color">> => Color,
|
||||
<<"license_number">> => Plate
|
||||
}
|
||||
},
|
||||
Map
|
||||
),
|
||||
?assertEqual(<<>>, Rest),
|
||||
?assertEqual(#{data => <<>>, phase => searching_head_hex7e}, State),
|
||||
ok.
|
||||
|
||||
t_case13_partial_0x7d_in_message(_Config) ->
|
||||
Parser = emqx_jt808_frame:initial_parse_state(#{}),
|
||||
Manuf = <<"examp">>,
|
||||
Model = <<"33333333333333333333">>,
|
||||
DevId = <<"1234567">>,
|
||||
Color = 3,
|
||||
Plate = <<"ujvl239">>,
|
||||
% pay attention to this
|
||||
AlarmInt = 16#7e,
|
||||
AlarmDigit = 16#7d,
|
||||
RegisterPacket =
|
||||
<<AlarmInt:?word, AlarmDigit:?word, Manuf/binary, Model/binary, DevId/binary, Color,
|
||||
Plate/binary>>,
|
||||
MsgId = 16#0100,
|
||||
PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>,
|
||||
MsgSn = 78,
|
||||
Size = size(RegisterPacket),
|
||||
Header =
|
||||
<<MsgId:?word, ?RESERVE:2, ?NO_FRAGMENT:1, ?NO_ENCRYPT:3, ?MSG_SIZE(Size), PhoneBCD/binary,
|
||||
MsgSn:?word>>,
|
||||
Stream = encode(Header, RegisterPacket),
|
||||
|
||||
<<Part1:15/binary, Part2/binary>> = Stream,
|
||||
<<_:14/binary, 16#7d:8>> = Part1,
|
||||
|
||||
{more, Parser2} = emqx_jt808_frame:parse(Part1, Parser),
|
||||
?assertMatch(#{phase := escaping_hex7d}, Parser2),
|
||||
{ok, Map, Rest, State} = emqx_jt808_frame:parse(Part2, Parser2),
|
||||
?assertEqual(
|
||||
#{
|
||||
<<"header">> => #{
|
||||
<<"msg_id">> => MsgId,
|
||||
<<"encrypt">> => ?NO_ENCRYPT,
|
||||
<<"phone">> => <<"000123456789">>,
|
||||
<<"len">> => Size,
|
||||
<<"msg_sn">> => MsgSn
|
||||
},
|
||||
<<"body">> => #{
|
||||
<<"province">> => AlarmInt,
|
||||
<<"city">> => AlarmDigit,
|
||||
<<"manufacturer">> => Manuf,
|
||||
<<"model">> => Model,
|
||||
<<"dev_id">> => DevId,
|
||||
<<"color">> => Color,
|
||||
<<"license_number">> => Plate
|
||||
}
|
||||
},
|
||||
Map
|
||||
),
|
||||
?assertEqual(<<>>, Rest),
|
||||
?assertEqual(#{data => <<>>, phase => searching_head_hex7e}, State),
|
||||
ok.
|
||||
|
||||
t_case14_custome_location_data(_) ->
|
||||
Bin =
|
||||
<<126, 2, 0, 0, 64, 1, 65, 72, 7, 53, 80, 3, 106, 0, 0, 0, 0, 0, 0, 0, 1, 1, 195, 232, 22,
|
||||
6, 89, 10, 16, 0, 0, 0, 0, 0, 0, 33, 6, 34, 9, 21, 69, 1, 4, 0, 0, 0, 0, 48, 1, 23, 49,
|
||||
1, 10, 235, 22, 0, 12, 0, 178, 137, 134, 4, 66, 25, 25, 144, 147, 71, 153, 0, 6, 0, 137,
|
||||
255, 255, 255, 255, 36, 126>>,
|
||||
Parser = emqx_jt808_frame:initial_parse_state(#{}),
|
||||
{ok, Packet, Rest, State} = emqx_jt808_frame:parse(Bin, Parser),
|
||||
?assertEqual(<<>>, Rest),
|
||||
?assertEqual(#{data => <<>>, phase => searching_head_hex7e}, State),
|
||||
_ = emqx_utils_json:encode(Packet).
|
||||
|
||||
t_case14_reserved_location_data(_) ->
|
||||
Bin =
|
||||
<<126, 2, 0, 0, 49, 1, 145, 114, 3, 130, 104, 2, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 211, 181,
|
||||
215, 6, 51, 228, 71, 0, 4, 0, 0, 0, 138, 34, 4, 25, 22, 5, 70, 1, 4, 0, 0, 0, 0, 5, 3,
|
||||
0, 0, 0, 48, 1, 31, 49, 1, 15, 130, 2, 0, 125, 2, 23, 126>>,
|
||||
Parser = emqx_jt808_frame:initial_parse_state(#{}),
|
||||
{ok, Packet, Rest, State} = emqx_jt808_frame:parse(Bin, Parser),
|
||||
?assertEqual(<<>>, Rest),
|
||||
?assertEqual(#{data => <<>>, phase => searching_head_hex7e}, State),
|
||||
_ = emqx_utils_json:encode(Packet).
|
||||
|
||||
t_case15_custome_client_query_ack(_) ->
|
||||
Bin =
|
||||
<<126, 1, 4, 2, 17, 78, 244, 128, 18, 137, 25, 0, 43, 0, 42, 52, 0, 0, 0, 1, 4, 0, 0, 0,
|
||||
180, 0, 0, 0, 8, 4, 0, 0, 1, 44, 0, 0, 0, 16, 5, 99, 109, 110, 101, 116, 0, 0, 0, 17, 0,
|
||||
0, 0, 0, 18, 0, 0, 0, 0, 19, 12, 52, 55, 46, 57, 57, 46, 57, 56, 46, 50, 53, 52, 0, 0,
|
||||
0, 23, 7, 48, 46, 48, 46, 48, 46, 48, 0, 0, 0, 24, 4, 0, 0, 31, 249, 0, 0, 0, 32, 4, 0,
|
||||
0, 0, 0, 0, 0, 0, 39, 4, 0, 0, 0, 30, 0, 0, 0, 41, 4, 0, 0, 0, 30, 0, 0, 0, 48, 4, 0, 0,
|
||||
0, 20, 0, 0, 0, 64, 1, 0, 0, 0, 0, 67, 1, 0, 0, 0, 0, 68, 1, 0, 0, 0, 0, 69, 4, 0, 0, 0,
|
||||
0, 0, 0, 0, 72, 1, 0, 0, 0, 0, 73, 1, 0, 0, 0, 0, 85, 4, 0, 0, 0, 120, 0, 0, 0, 86, 4,
|
||||
0, 0, 0, 20, 0, 0, 0, 93, 2, 0, 30, 0, 0, 0, 128, 4, 0, 0, 136, 203, 0, 0, 0, 129, 2, 0,
|
||||
0, 0, 0, 0, 130, 2, 0, 0, 0, 0, 0, 131, 0, 0, 0, 0, 132, 1, 0, 0, 0, 240, 1, 2, 16, 0,
|
||||
0, 0, 240, 2, 2, 3, 57, 0, 0, 240, 3, 1, 41, 0, 0, 240, 4, 2, 0, 116, 0, 0, 240, 5, 4,
|
||||
0, 53, 111, 127, 0, 0, 240, 6, 4, 0, 3, 51, 18, 0, 0, 240, 7, 1, 1, 0, 0, 240, 8, 2, 0,
|
||||
30, 0, 0, 240, 10, 2, 0, 30, 0, 0, 240, 11, 6, 0, 0, 0, 0, 0, 0, 0, 0, 240, 12, 1, 1, 0,
|
||||
0, 240, 13, 18, 117, 112, 103, 114, 97, 100, 101, 46, 99, 112, 115, 100, 110, 97, 46,
|
||||
99, 111, 109, 0, 0, 240, 14, 4, 0, 0, 123, 40, 0, 0, 240, 15, 1, 1, 0, 0, 240, 16, 3, 0,
|
||||
16, 3, 0, 0, 240, 17, 2, 0, 32, 0, 0, 240, 18, 3, 0, 22, 40, 0, 0, 240, 19, 4, 0, 17,
|
||||
25, 32, 0, 0, 240, 20, 3, 55, 0, 10, 0, 0, 240, 21, 1, 50, 0, 0, 240, 22, 2, 3, 25, 0,
|
||||
0, 240, 23, 2, 30, 50, 0, 0, 240, 24, 21, 48, 44, 48, 44, 53, 56, 46, 50, 49, 53, 46,
|
||||
53, 48, 46, 53, 48, 44, 54, 48, 48, 56, 0, 0, 241, 1, 1, 160, 0, 0, 241, 2, 1, 130, 0,
|
||||
0, 255, 148, 93, 14, 22, 1, 56, 57, 56, 54, 48, 52, 57, 53, 49, 48, 50, 49, 55, 48, 51,
|
||||
48, 52, 53, 53, 56, 17, 2, 52, 54, 48, 48, 56, 49, 53, 56, 51, 52, 48, 52, 53, 53, 56,
|
||||
4, 3, 0, 1, 3, 5, 0, 3, 6, 0, 3, 7, 0, 5, 8, 3, 0, 1, 5, 8, 14, 0, 0, 5, 8, 15, 0, 0, 5,
|
||||
8, 41, 0, 0, 5, 8, 48, 0, 0, 5, 8, 42, 0, 0, 5, 8, 43, 0, 0, 5, 8, 4, 0, 0, 138, 126>>,
|
||||
Parser = emqx_jt808_frame:initial_parse_state(#{}),
|
||||
{ok, Packet, Rest, State} = emqx_jt808_frame:parse(Bin, Parser),
|
||||
?assertEqual(<<>>, Rest),
|
||||
?assertEqual(#{data => <<>>, phase => searching_head_hex7e}, State),
|
||||
_ = emqx_utils_json:encode(Packet).
|
||||
|
||||
encode(Header, Body) ->
|
||||
S1 = <<Header/binary, Body/binary>>,
|
||||
Crc = make_crc(S1, undefined),
|
||||
S2 = do_escape(<<S1/binary, Crc:8>>),
|
||||
Stream = <<16#7e:8, S2/binary, 16#7e:8>>,
|
||||
%?LOGT("encode a packet=~p", [binary_to_hex_string(Stream)]),
|
||||
Stream.
|
||||
|
||||
make_crc(<<>>, Xor) ->
|
||||
?LOGT("crc is ~p", [Xor]),
|
||||
Xor;
|
||||
make_crc(<<C:8, Rest/binary>>, undefined) ->
|
||||
make_crc(Rest, C);
|
||||
make_crc(<<C:8, Rest/binary>>, Xor) ->
|
||||
make_crc(Rest, C bxor Xor).
|
||||
|
||||
do_escape(Binary) ->
|
||||
do_escape(Binary, <<>>).
|
||||
|
||||
do_escape(<<>>, Acc) ->
|
||||
Acc;
|
||||
do_escape(<<16#7e, Rest/binary>>, Acc) ->
|
||||
do_escape(Rest, <<Acc/binary, 16#7d, 16#02>>);
|
||||
do_escape(<<16#7d, Rest/binary>>, Acc) ->
|
||||
do_escape(Rest, <<Acc/binary, 16#7d, 16#01>>);
|
||||
do_escape(<<C, Rest/binary>>, Acc) ->
|
||||
do_escape(Rest, <<Acc/binary, C:8>>).
|
||||
|
||||
binary_to_hex_string(Data) ->
|
||||
lists:flatten([io_lib:format("~2.16.0B ", [X]) || <<X:8>> <= Data]).
|
Loading…
Reference in New Issue