test(gw_jt808): frame parser and channel SUITE

This commit is contained in:
JimMoen 2023-11-08 19:25:59 +08:00
parent 4d493292fb
commit dc64068e41
No known key found for this signature in database
GPG Key ID: 87A520B4F76BA86D
3 changed files with 3472 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@ -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}.

View File

@ -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]).