%%-------------------------------------------------------------------- %% Copyright (c) 2023-2024 EMQ Technologies Co., Ltd. All Rights Reserved. %%-------------------------------------------------------------------- -module(emqx_jt808_SUITE). -compile(export_all). -compile(nowarn_export_all). -include("emqx_jt808.hrl"). -include_lib("emqx/include/emqx.hrl"). -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). -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). -define(PORT, 6207). -define(PORT_STR, "6207"). -define(LOGT(Format, Args), ct:pal("TEST_SUITE: " ++ Format, Args)). -define(PROTO_REG_SERVER_HOST, "http://127.0.0.1:8991"). -define(PROTO_REG_AUTH_PATH, "/jt808/auth"). -define(PROTO_REG_REGISTRY_PATH, "/jt808/registry"). -define(JT808_PHONE, "000123456789"). %% <<"jt808/000123456789/">> -define(JT808_MOUNTPOINT, "jt808/" ?JT808_PHONE "/"). %% <<"jt808/000123456789/000123456789/up">> -define(JT808_UP_TOPIC, <>). %% <<"jt808/000123456789/000123456789/dn">> -define(JT808_DN_TOPIC, <>). %% erlfmt-ignore -define(CONF_DEFAULT, <<" gateway.jt808 { listeners.tcp.default { bind = ", ?PORT_STR, " } proto { auth { allow_anonymous = false registry = \"", ?PROTO_REG_SERVER_HOST, ?PROTO_REG_REGISTRY_PATH, "\" authentication = \"", ?PROTO_REG_SERVER_HOST, ?PROTO_REG_AUTH_PATH, "\" } } } ">>). %% erlfmt-ignore -define(CONF_ANONYMOUS, <<" gateway.jt808 { listeners.tcp.default { bind = ", ?PORT_STR, " } proto { auth { allow_anonymous = true } } } ">>). all() -> emqx_common_test_helpers:all(?MODULE). init_per_suite(Config) -> Config. end_per_suite(_Config) -> ok. init_per_testcase(Case = t_case02_anonymous_register_and_auth, Config) -> Apps = boot_apps(Case, ?CONF_ANONYMOUS, Config), [{suite_apps, Apps} | Config]; init_per_testcase(Case, Config) when Case =:= t_create_ALLOW_invalid_auth_config; Case =:= t_create_DISALLOW_invalid_auth_config -> Apps = boot_apps(Case, <<>>, Config), [{suite_apps, Apps} | Config]; init_per_testcase(Case, Config) -> Apps = boot_apps(Case, ?CONF_DEFAULT, Config), [{suite_apps, Apps} | Config]. end_per_testcase(_Case, Config) -> try ok = emqx_jt808_auth_http_test_server:stop() catch exit:noproc -> ok end, ok = emqx_cth_suite:stop(?config(suite_apps, Config)), ok. boot_apps(Case, JT808Conf, Config) -> Apps = emqx_cth_suite:start( [ emqx, {emqx_conf, JT808Conf}, emqx_gateway ], #{work_dir => emqx_cth_suite:work_dir(Case, Config)} ), {ok, _Pid} = emqx_jt808_auth_http_test_server:start_link(), timer:sleep(1000), Apps. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% helper functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% gen_packet(Header, Body) -> S1 = <
>, Crc = make_crc(S1, undefined), S2 = do_escape(<>), 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(<>, undefined) -> make_crc(Rest, C); make_crc(<>, 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, <>); do_escape(<<16#7d, Rest/binary>>, Acc) -> do_escape(Rest, <>); do_escape(<>, Acc) -> do_escape(Rest, <>). client_regi_procedure(Socket) -> client_regi_procedure(Socket, <<"123456">>). client_regi_procedure(Socket, ExpectedCode) -> % % send REGISTER % 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 = ?MC_REGISTER, PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, MsgSn = 78, Size = size(RegisterPacket), Header = <>, S1 = gen_packet(Header, RegisterPacket), ok = gen_tcp:send(Socket, S1), {ok, Packet} = gen_tcp:recv(Socket, 0, 500), AckPacket = <>, Size2 = size(AckPacket), MsgId2 = ?MS_REGISTER_ACK, MsgSn2 = 0, Header2 = <>, S2 = gen_packet(Header2, AckPacket), ?LOGT("S2=~p", [binary_to_hex_string(S2)]), ?LOGT("Packet=~p", [binary_to_hex_string(Packet)]), ?assertEqual(S2, Packet), {ok, ExpectedCode}. client_auth_procedure(Socket, AuthCode) -> ?LOGT("start auth procedure", []), % % send AUTH % PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, MsgId = ?MC_AUTH, MsgSn = 78, Size = size(AuthCode), Header = <>, S1 = gen_packet(Header, AuthCode), ?LOGT("auth S1=~p", [S1]), ok = gen_tcp:send(Socket, S1), %% timer:sleep(200), {ok, Packet} = gen_tcp:recv(Socket, 0, 500), % receive general response GenAckPacket = <>, Size2 = size(GenAckPacket), MsgId2 = ?MS_GENERAL_RESPONSE, MsgSn2 = 1, Header2 = <>, S2 = gen_packet(Header2, GenAckPacket), ?assertEqual(S2, Packet), ?assert(lists:member(?JT808_DN_TOPIC, emqx:topics())), ?LOGT("============= auth procedure success ===============", []). client_send_general_response(Socket, MsgId3, MsgSn3, PhoneBCD) -> GenAckPacket4 = <>, Size4 = size(GenAckPacket4), MsgId4 = ?MC_GENERAL_RESPONSE, MsgSn4 = 1, Header4 = <>, S4 = gen_packet(Header4, GenAckPacket4), ?LOGT("S4 = ~p", [S4]), ok = gen_tcp:send(Socket, S4), ok. location_report() -> Alarm = 2, Status = 3, Latitude = 1000, Longitude = 1001, Altitude = 2000, Speed = 135, Direction = 32, TimeBCD = <<16#17, 16#10, 16#22, 16#11, 16#15, 16#53>>, Time = <<"171022111553">>, MileAge = 12379, FuelMeter = 972, Speed2 = 29, AlarmID = 18, OA_Type = 2, OA_Id = 29, IOA_Type = 8, IOA_Id = 23, IOA_Direction = 89, PTA_ID = 45, PTA_Time = 21, PTA_Result = 1, Binary = <>, Json = #{ <<"alarm">> => Alarm, <<"status">> => Status, <<"latitude">> => Latitude, <<"longitude">> => Longitude, <<"altitude">> => Altitude, <<"speed">> => Speed, <<"direction">> => Direction, <<"time">> => Time, <<"extra">> => #{ <<"mileage">> => MileAge, <<"fuel_meter">> => FuelMeter, <<"speed">> => Speed2, <<"alarm_id">> => AlarmID, <<"overspeed_alarm">> => #{ <<"type">> => OA_Type, <<"id">> => OA_Id }, <<"in_out_alarm">> => #{ <<"type">> => IOA_Type, <<"id">> => IOA_Id, <<"direction">> => IOA_Direction }, <<"path_time_alarm">> => #{ <<"id">> => PTA_ID, <<"time">> => PTA_Time, <<"result">> => PTA_Result } } }, {Binary, Json}. location_report_28bytes() -> Alarm = 2, Status = 3, Latitude = 1000, Longitude = 1001, Altitude = 2000, Speed = 135, Direction = 32, TimeBCD = <<16#17, 16#10, 16#22, 16#11, 16#15, 16#53>>, Time = <<"171022111553">>, Binary = <>, Json = #{ <<"alarm">> => Alarm, <<"status">> => Status, <<"latitude">> => Latitude, <<"longitude">> => Longitude, <<"altitude">> => Altitude, <<"speed">> => Speed, <<"direction">> => Direction, <<"time">> => Time }, {Binary, Json}. binary_to_hex_string(Data) -> lists:flatten([io_lib:format("~2.16.0B ", [X]) || <> <= Data]). receive_msg() -> receive {deliver, Topic, #message{payload = Payload}} -> {Topic, Payload} after 100 -> {error, timeout} end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%% test cases %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% t_case00_register(_) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ?assertEqual(AuthCode, <<"123456">>), ok = gen_tcp:close(Socket). t_case01_auth(_) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}, {nodelay, true}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), ok = gen_tcp:close(Socket). t_case02_anonymous_register_and_auth(_) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket, <<>>), ?assertEqual(AuthCode, <<>>), ok = client_auth_procedure(Socket, AuthCode), ok = gen_tcp:close(Socket). t_case03_heartbeat(_) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, % % send heartbeat % MsgId = ?MC_HEARTBEAT, MsgSn = 78, Size = 0, Header = <>, S1 = gen_packet(Header, <<>>), ok = gen_tcp:send(Socket, S1), %% timer:sleep(200), {ok, Packet} = gen_tcp:recv(Socket, 0, 500), GenAckPacket = <>, Size2 = size(GenAckPacket), MsgId2 = ?MS_GENERAL_RESPONSE, MsgSn2 = 2, Header2 = <>, S2 = gen_packet(Header2, GenAckPacket), ?assertEqual(S2, Packet), ok = gen_tcp:close(Socket). t_case04(_) -> ok = emqx:subscribe(?JT808_UP_TOPIC), {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, %% send event report EventReportId = 98, MsgBody3 = <>, MsgId3 = ?MC_EVENT_REPORT, MsgSn3 = 79, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), ok = gen_tcp:send(Socket, S3), {ok, Packet4} = gen_tcp:recv(Socket, 0, 500), % receive general response GenAckPacket4 = <>, Size4 = size(GenAckPacket4), MsgId4 = ?MS_GENERAL_RESPONSE, MsgSn4 = 2, Header4 = <>, S4 = gen_packet(Header4, GenAckPacket4), ?assertEqual(S4, Packet4), timer:sleep(100), {?JT808_UP_TOPIC, Payload} = receive_msg(), ?assertEqual( #{ <<"header">> => #{ <<"msg_id">> => MsgId3, <<"encrypt">> => ?NO_ENCRYPT, <<"phone">> => <<"000123456789">>, <<"len">> => Size3, <<"msg_sn">> => MsgSn3 }, <<"body">> => #{<<"id">> => EventReportId} }, emqx_utils_json:decode(Payload, [return_maps]) ), ok = gen_tcp:close(Socket). t_case05(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, Flag = 15, Text = <<"who are you">>, DlCommand = #{ <<"header">> => #{<<"msg_id">> => ?MS_SEND_TEXT}, <<"body">> => #{<<"flag">> => Flag, <<"text">> => Text} }, emqx:publish(emqx_message:make(?JT808_DN_TOPIC, emqx_utils_json:encode(DlCommand))), % % client get downlink "send text" % MsgBody3 = <>, MsgId3 = ?MS_SEND_TEXT, MsgSn3 = 2, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), ?LOGT("S3=~p", [S3]), %% timer:sleep(600), {ok, Packet3} = gen_tcp:recv(Socket, 0, 500), ?assertEqual(S3, Packet3), % client send "client general response" GenAckPacket4 = <>, Size4 = size(GenAckPacket4), MsgId4 = ?MC_GENERAL_RESPONSE, MsgSn4 = 2, Header4 = <>, S4 = gen_packet(Header4, GenAckPacket4), ?LOGT("S4 = ~p", [S4]), ok = gen_tcp:send(Socket, S4), %% timer:sleep(300), ok = gen_tcp:close(Socket). t_case06_downlink_retx(_) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, Flag = 15, Text = <<"who are you">>, DlCommand = #{ <<"header">> => #{<<"msg_id">> => ?MS_SEND_TEXT}, <<"body">> => #{<<"flag">> => Flag, <<"text">> => Text} }, emqx:publish(emqx_message:make(?JT808_DN_TOPIC, emqx_utils_json:encode(DlCommand))), % % client get downlink "send text" % MsgBody3 = <>, MsgId3 = ?MS_SEND_TEXT, MsgSn3 = 2, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), ?LOGT("S3=~p", [S3]), %% wait emqx-jt808 to retx "send text" timer:sleep(100), {ok, Packet3} = gen_tcp:recv(Socket, 0, 500), ?assertEqual(S3, Packet3), % client send "client general response" GenAckPacket4 = <>, Size4 = size(GenAckPacket4), MsgId4 = ?MC_GENERAL_RESPONSE, MsgSn4 = 2, Header4 = <>, S4 = gen_packet(Header4, GenAckPacket4), ?LOGT("S4 = ~p", [S4]), ok = gen_tcp:send(Socket, S4), %% timer:sleep(300), % wait again, there should be no retx packet %% timer:sleep(10000), {error, timeout} = gen_tcp:recv(Socket, 0, 500), ok = gen_tcp:close(Socket). t_case07_dl_0x8302_send_question(_) -> ok = emqx:subscribe(?JT808_UP_TOPIC), {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, Flag = 16#10, Question = <<"who are you">>, Length = size(Question), DlCommand = #{ <<"header">> => #{<<"msg_id">> => ?MS_SEND_QUESTION}, <<"body">> => #{ <<"flag">> => Flag, <<"length">> => Length, <<"question">> => Question, <<"answers">> => [ #{<<"id">> => 1, <<"len">> => 3, <<"answer">> => <<"Tom">>}, #{<<"id">> => 2, <<"len">> => 4, <<"answer">> => <<"Mike">>} ] } }, emqx:publish(emqx_message:make(?JT808_DN_TOPIC, emqx_utils_json:encode(DlCommand))), %% client get downlink "send text" MsgBody3 = <>/binary, 2:8, 4:?WORD, <<"Mike">>/binary>>, MsgId3 = ?MS_SEND_QUESTION, MsgSn3 = 2, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), timer:sleep(600), {ok, Packet3} = gen_tcp:recv(Socket, 0, 500), ?assertEqual(S3, Packet3), % client send "client answer" Answer = <>, Size4 = size(Answer), MsgId4 = ?MC_QUESTION_ACK, MsgSn4 = 2, Header4 = <>, S4 = gen_packet(Header4, Answer), ok = gen_tcp:send(Socket, S4), timer:sleep(100), {?JT808_UP_TOPIC, Payload} = receive_msg(), ?assertEqual( #{ <<"header">> => #{ <<"msg_id">> => MsgId4, <<"encrypt">> => ?NO_ENCRYPT, <<"phone">> => <<"000123456789">>, <<"len">> => Size4, <<"msg_sn">> => MsgSn4 }, <<"body">> => #{<<"seq">> => MsgSn3, <<"id">> => 2} }, emqx_utils_json:decode(Payload, [return_maps]) ), ok = gen_tcp:close(Socket). t_case08_dl_0x8500_vehicle_ctrl(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, ok = emqx:subscribe(?JT808_UP_TOPIC), Flag = 16#0, DlCommand = #{ <<"header">> => #{<<"msg_id">> => ?MS_VEHICLE_CONTROL}, <<"body">> => #{<<"flag">> => Flag} }, emqx:publish(emqx_message:make(?JT808_DN_TOPIC, emqx_utils_json:encode(DlCommand))), % % client get downlink "vehicle ctrl" % MsgBody3 = <>, MsgId3 = ?MS_VEHICLE_CONTROL, MsgSn3 = 2, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), timer:sleep(600), {ok, Packet3} = gen_tcp:recv(Socket, 0, 500), ?assertEqual(S3, Packet3), % client send "client answer" CtrlAck = <<126, 5, 0, 0, 30, 1, 136, 118, 99, 137, 114, 1, 244, 0, 7, 0, 0, 0, 0, 0, 4, 0, 0, 1, 49, 122, 103, 6, 147, 104, 81, 0, 24, 0, 0, 0, 121, 23, 16, 32, 18, 3, 25, 69, 126>>, ?LOGT("S4 = ~p", [CtrlAck]), ok = gen_tcp:send(Socket, CtrlAck), timer:sleep(300), {?JT808_UP_TOPIC, Payload} = receive_msg(), ?assertEqual( #{ <<"header">> => #{ <<"encrypt">> => 0, <<"len">> => 30, <<"msg_id">> => 1280, <<"msg_sn">> => 500, <<"phone">> => <<"018876638972">> }, <<"body">> => #{ <<"seq">> => 7, <<"location">> => #{ <<"alarm">> => 0, <<"altitude">> => 24, <<"direction">> => 121, <<"latitude">> => 20019815, <<"longitude">> => 110323793, <<"speed">> => 0, <<"status">> => 262144, <<"time">> => <<"171020120319">> } } }, emqx_utils_json:decode(Payload, [return_maps]) ), ok = gen_tcp:close(Socket). t_case09_dl_0x8103_set_client_param(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, Length = 2, DlCommand = #{ <<"header">> => #{<<"msg_id">> => ?MS_SET_CLIENT_PARAM}, <<"body">> => #{ <<"length">> => Length, <<"params">> => [ #{<<"id">> => 16#0013, <<"value">> => <<"www.example.com">>}, #{<<"id">> => 16#0059, <<"value">> => 1200} ] } }, emqx:publish(emqx_message:make(?JT808_DN_TOPIC, emqx_utils_json:encode(DlCommand))), % % client get downlink "vehicle ctrl" % MsgBody3 = <>/binary, 16#0059:?DWORD, 4:8, 1200:?DWORD>>, MsgId3 = ?MS_SET_CLIENT_PARAM, MsgSn3 = 2, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), timer:sleep(600), {ok, Packet3} = gen_tcp:recv(Socket, 0, 500), ?LOGT(" S3=~p", [binary_to_hex_string(S3)]), ?LOGT("Packet3=~p", [binary_to_hex_string(Packet3)]), ?assertEqual(S3, Packet3), ?LOGT("client receive command from server ~p", [S3]), % client send "general response" GenAckPacket4 = <>, Size4 = size(GenAckPacket4), MsgId4 = ?MC_GENERAL_RESPONSE, MsgSn4 = 1, Header4 = <>, S4 = gen_packet(Header4, GenAckPacket4), ?LOGT("S4 = ~p", [S4]), ok = gen_tcp:send(Socket, S4), % no retrasmition of 0x8103 %% timer:sleep(10000), {error, timeout} = gen_tcp:recv(Socket, 0, 500), ok = gen_tcp:close(Socket). t_case10_dl_0x8104_query_client_all_param(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, DlCommand = #{ <<"header">> => #{<<"msg_id">> => ?MS_CLIENT_CONTROL}, <<"body">> => #{<<"command">> => 200, <<"param">> => <<"ABCD">>} }, emqx:publish(emqx_message:make(?JT808_DN_TOPIC, emqx_utils_json:encode(DlCommand))), % % client get downlink command % MsgBody3 = <<200:8, <<"ABCD">>/binary>>, MsgId3 = ?MS_CLIENT_CONTROL, MsgSn3 = 2, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), %% timer:sleep(600), {ok, Packet3} = gen_tcp:recv(Socket, 0, 500), ?LOGT(" S3=~p", [binary_to_hex_string(S3)]), ?LOGT("Packet3=~p", [binary_to_hex_string(Packet3)]), ?assertEqual(S3, Packet3), ?LOGT("client receive command from server ~p", [S3]), % client send ack client_send_general_response(Socket, MsgId3, MsgSn3, PhoneBCD), %% timer:sleep(200), % no retrasmition of downlink message %% timer:sleep(10000), {error, timeout} = gen_tcp:recv(Socket, 0, 500), ok = gen_tcp:close(Socket). t_case11_dl_0x8106_query_client_param(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, ok = emqx:subscribe(?JT808_UP_TOPIC), DlCommand = #{ <<"header">> => #{<<"msg_id">> => ?MS_QUERY_CLIENT_PARAM}, <<"body">> => #{<<"length">> => 2, <<"ids">> => [16#0092, 16#0031]} }, emqx:publish(emqx_message:make(?JT808_DN_TOPIC, emqx_utils_json:encode(DlCommand))), % % client get downlink command % MsgBody3 = <<2:8, 16#0092:?DWORD, 16#0031:?DWORD>>, MsgId3 = ?MS_QUERY_CLIENT_PARAM, MsgSn3 = 2, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), {ok, Packet3} = gen_tcp:recv(Socket, 0, 500), ?LOGT(" S3=~p", [binary_to_hex_string(S3)]), ?LOGT("Packet3=~p", [binary_to_hex_string(Packet3)]), ?assertEqual(S3, Packet3), ?LOGT("client receive command from server ~p", [S3]), UlPacket4 = <>, Size4 = size(UlPacket4), MsgId4 = ?MC_QUERY_PARAM_ACK, MsgSn4 = 2, Header4 = <>, S4 = gen_packet(Header4, UlPacket4), ?LOGT("S4 = ~p", [S4]), ok = gen_tcp:send(Socket, S4), {?JT808_UP_TOPIC, Payload} = receive_msg(), ?assertEqual( #{ <<"header">> => #{ <<"encrypt">> => 0, <<"len">> => Size4, <<"msg_id">> => ?MC_QUERY_PARAM_ACK, <<"msg_sn">> => 2, <<"phone">> => <<"000123456789">> }, <<"body">> => #{ <<"seq">> => MsgSn3, <<"length">> => 2, <<"params">> => [ #{<<"id">> => 16#0031, <<"value">> => 379}, #{<<"id">> => 16#0092, <<"value">> => 2} ] } }, emqx_utils_json:decode(Payload, [return_maps]) ), %% timer:sleep(200), % no retrasmition of downlink message %% timer:sleep(10000), {error, timeout} = gen_tcp:recv(Socket, 0, 500), ok = gen_tcp:close(Socket). t_case11_dl_0x8107_query_client_attrib(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, ok = emqx:subscribe(?JT808_UP_TOPIC), DlCommand = #{<<"header">> => #{<<"msg_id">> => ?MS_QUERY_CLIENT_ATTRIB}}, emqx:publish(emqx_message:make(?JT808_DN_TOPIC, emqx_utils_json:encode(DlCommand))), % % client get downlink command % MsgBody3 = <<>>, MsgId3 = ?MS_QUERY_CLIENT_ATTRIB, MsgSn3 = 2, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), timer:sleep(100), {ok, Packet3} = gen_tcp:recv(Socket, 0, 500), ?LOGT(" S3=~p", [binary_to_hex_string(S3)]), ?LOGT("Packet3=~p", [binary_to_hex_string(Packet3)]), ?assertEqual(S3, Packet3), ?LOGT("client receive command from server ~p", [S3]), UlPacket4 = <<12:?WORD, <<"manu3">>/binary, <<"A1B2C3D4E5F6G7H8I9J0">>:20/binary, <<"dev1234">>:7/binary, <<16#33, 16#33, 16#33, 16#33, 16#33, 16#44, 16#44, 16#44, 16#44, 16#44>>:10/binary, 6:8, <<"v2.3.7">>:6/binary, 5:8, <<"v1.26">>:5/binary, 101:8, 102:8>>, Size4 = size(UlPacket4), MsgId4 = ?MC_QUERY_ATTRIB_ACK, MsgSn4 = 2, Header4 = <>, S4 = gen_packet(Header4, UlPacket4), ?LOGT("S4 = ~p", [S4]), ok = gen_tcp:send(Socket, S4), timer:sleep(100), {?JT808_UP_TOPIC, Payload} = receive_msg(), ?assertEqual( #{ <<"header">> => #{ <<"encrypt">> => 0, <<"len">> => Size4, <<"msg_id">> => ?MC_QUERY_ATTRIB_ACK, <<"msg_sn">> => 2, <<"phone">> => <<"000123456789">> }, <<"body">> => #{ <<"type">> => 12, <<"manufacturer">> => <<"manu3">>, <<"model">> => <<"A1B2C3D4E5F6G7H8I9J0">>, <<"id">> => <<"dev1234">>, <<"iccid">> => <<"33333333334444444444">>, <<"hardware_version">> => <<"v2.3.7">>, <<"firmware_version">> => <<"v1.26">>, <<"gnss_prop">> => 101, <<"comm_prop">> => 102 } }, emqx_utils_json:decode(Payload, [return_maps]) ), % no retrasmition of downlink message %% timer:sleep(10000), {error, timeout} = gen_tcp:recv(Socket, 0, 500), ok = gen_tcp:close(Socket). t_case15_dl_0x8201_query_location(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, ok = emqx:subscribe(?JT808_UP_TOPIC), DlCommand = #{<<"header">> => #{<<"msg_id">> => ?MS_QUERY_LOCATION}}, emqx:publish(emqx_message:make(?JT808_DN_TOPIC, emqx_utils_json:encode(DlCommand))), % % client get downlink command % MsgBody3 = <<>>, MsgId3 = ?MS_QUERY_LOCATION, MsgSn3 = 2, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), {ok, Packet3} = gen_tcp:recv(Socket, 0, 500), ?LOGT(" S3=~p", [binary_to_hex_string(S3)]), ?LOGT("Packet3=~p", [binary_to_hex_string(Packet3)]), ?assertEqual(S3, Packet3), ?LOGT("client receive command from server ~p", [S3]), {LocationReportBinary, LocationReportJson} = location_report(), UlPacket4 = <>, Size4 = size(UlPacket4), MsgId4 = ?MC_QUERY_LOCATION_ACK, MsgSn4 = 2, Header4 = <>, S4 = gen_packet(Header4, UlPacket4), ?LOGT("S4 = ~p", [S4]), ok = gen_tcp:send(Socket, S4), timer:sleep(100), {?JT808_UP_TOPIC, Payload} = receive_msg(), ?assertEqual( #{ <<"header">> => #{ <<"encrypt">> => 0, <<"len">> => Size4, <<"msg_id">> => ?MC_QUERY_LOCATION_ACK, <<"msg_sn">> => 2, <<"phone">> => <<"000123456789">> }, <<"body">> => #{ <<"seq">> => MsgSn3, <<"params">> => LocationReportJson } }, emqx_utils_json:decode(Payload, [return_maps]) ), %% timer:sleep(200), % no retrasmition of downlink message %% timer:sleep(10000), {error, timeout} = gen_tcp:recv(Socket, 0, 500), ok = gen_tcp:close(Socket). t_location_report(_) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, ok = emqx:subscribe(?JT808_UP_TOPIC), {LocationReportBinary, LocationReportJson} = location_report(), UlPacket = <>, Size = size(UlPacket), MsgId = ?MC_LOCATION_REPORT, MsgSn = 1, Header = <>, S = gen_packet(Header, UlPacket), ?LOGT("S = ~p", [S]), ok = gen_tcp:send(Socket, S), timer:sleep(100), {?JT808_UP_TOPIC, Payload} = receive_msg(), ?assertEqual( #{ <<"header">> => #{ <<"encrypt">> => 0, <<"len">> => Size, <<"msg_id">> => ?MC_LOCATION_REPORT, <<"msg_sn">> => MsgSn, <<"phone">> => <<"000123456789">> }, <<"body">> => LocationReportJson }, emqx_utils_json:decode(Payload, [return_maps]) ), % receive general response {ok, Packet} = gen_tcp:recv(Socket, 0, 500), GenAckPacket = <>, Size2 = size(GenAckPacket), MsgId2 = ?MS_GENERAL_RESPONSE, MsgSn2 = 2, Header2 = <>, S2 = gen_packet(Header2, GenAckPacket), ?assertEqual(S2, Packet), % no retrasmition of downlink message {error, timeout} = gen_tcp:recv(Socket, 0, 500), ok = gen_tcp:close(Socket). t_case15_dl_0x8202_trace_location(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, DlCommand = #{ <<"header">> => #{<<"msg_id">> => ?MS_TRACE_LOCATION}, <<"body">> => #{<<"period">> => 23, <<"expiry">> => 183} }, emqx:publish(emqx_message:make(?JT808_DN_TOPIC, emqx_utils_json:encode(DlCommand))), % % client get downlink command % MsgBody3 = <<23:?WORD, 183:?DWORD>>, MsgId3 = ?MS_TRACE_LOCATION, MsgSn3 = 2, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), %% timer:sleep(600), {ok, Packet3} = gen_tcp:recv(Socket, 0, 500), ?LOGT(" S3=~p", [binary_to_hex_string(S3)]), ?LOGT("Packet3=~p", [binary_to_hex_string(Packet3)]), ?assertEqual(S3, Packet3), ?LOGT("client receive command from server ~p", [S3]), client_send_general_response(Socket, MsgId3, MsgSn3, PhoneBCD), % no retrasmition of downlink message %% timer:sleep(10000), {error, timeout} = gen_tcp:recv(Socket, 0, 500), ok = gen_tcp:close(Socket). t_case50_ul_0x0303_info_request_cancel(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, ok = emqx:subscribe(?JT808_UP_TOPIC), % % send event report % MsgBody3 = <<1:8, 6:8>>, MsgId3 = ?MC_INFO_REQ_CANCEL, MsgSn3 = 79, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), ok = gen_tcp:send(Socket, S3), %%timer:sleep(600), {ok, Packet4} = gen_tcp:recv(Socket, 0, 500), % receive general response GenAckPacket4 = <>, Size4 = size(GenAckPacket4), MsgId4 = ?MS_GENERAL_RESPONSE, MsgSn4 = 2, Header4 = <>, S4 = gen_packet(Header4, GenAckPacket4), ?assertEqual(S4, Packet4), {?JT808_UP_TOPIC, Payload} = receive_msg(), ?assertEqual( #{ <<"header">> => #{ <<"msg_id">> => MsgId3, <<"encrypt">> => ?NO_ENCRYPT, <<"phone">> => <<"000123456789">>, <<"len">> => Size3, <<"msg_sn">> => MsgSn3 }, <<"body">> => #{<<"id">> => 1, <<"flag">> => 6} }, emqx_utils_json:decode(Payload, [return_maps]) ), ok = gen_tcp:close(Socket). t_case51_ul_0x0701_waybill_report(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, ok = emqx:subscribe(?JT808_UP_TOPIC), % % send event report % MsgBody3 = <<7:?DWORD, <<"ABCDEFG">>/binary>>, MsgId3 = ?MC_WAYBILL_REPORT, MsgSn3 = 79, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), ok = gen_tcp:send(Socket, S3), %% timer:sleep(600), {ok, Packet4} = gen_tcp:recv(Socket, 0, 500), % receive general response GenAckPacket4 = <>, Size4 = size(GenAckPacket4), MsgId4 = ?MS_GENERAL_RESPONSE, MsgSn4 = 2, Header4 = <>, S4 = gen_packet(Header4, GenAckPacket4), ?assertEqual(S4, Packet4), {?JT808_UP_TOPIC, Payload} = receive_msg(), ?assertEqual( #{ <<"header">> => #{ <<"msg_id">> => MsgId3, <<"encrypt">> => ?NO_ENCRYPT, <<"phone">> => <<"000123456789">>, <<"len">> => Size3, <<"msg_sn">> => MsgSn3 }, <<"body">> => #{<<"length">> => 7, <<"data">> => base64:encode(<<"ABCDEFG">>)} }, emqx_utils_json:decode(Payload, [return_maps]) ), ok = gen_tcp:close(Socket). t_case52_ul_0x0705_can_bus_report(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, ok = emqx:subscribe(?JT808_UP_TOPIC), % % send event report % MsgBody3 = <<2:?WORD, <<16#09, 16#23, 16#46, 16#07, 16#25>>/binary, 0:1, 1:1, 0:1, 35:29, <<"11111111">>/binary, 1:1, 0:1, 1:1, 36:29, <<"22222222">>/binary>>, MsgId3 = ?MC_CAN_BUS_REPORT, MsgSn3 = 79, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), ok = gen_tcp:send(Socket, S3), %% timer:sleep(600), {ok, Packet4} = gen_tcp:recv(Socket, 0, 500), % receive general response GenAckPacket4 = <>, Size4 = size(GenAckPacket4), MsgId4 = ?MS_GENERAL_RESPONSE, MsgSn4 = 2, Header4 = <>, S4 = gen_packet(Header4, GenAckPacket4), ?assertEqual(S4, Packet4), {?JT808_UP_TOPIC, Payload} = receive_msg(), ?assertEqual( #{ <<"header">> => #{ <<"msg_id">> => MsgId3, <<"encrypt">> => ?NO_ENCRYPT, <<"phone">> => <<"000123456789">>, <<"len">> => Size3, <<"msg_sn">> => MsgSn3 }, <<"body">> => #{ <<"length">> => 2, <<"time">> => <<"0923460725">>, <<"can_data">> => [ #{ <<"channel">> => 0, <<"frame_type">> => 1, <<"data_method">> => 0, <<"id">> => 35, <<"data">> => base64:encode(<<"11111111">>) }, #{ <<"channel">> => 1, <<"frame_type">> => 0, <<"data_method">> => 1, <<"id">> => 36, <<"data">> => base64:encode(<<"22222222">>) } ] } }, emqx_utils_json:decode(Payload, [return_maps]) ), ok = gen_tcp:close(Socket). t_case53_ul_0x0800_multimedia_event_report(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, ok = emqx:subscribe(?JT808_UP_TOPIC), % % send event report % MsgBody3 = <<65:?DWORD, 2:8, 1:8, 4:8, 103:8>>, MsgId3 = ?MC_MULTIMEDIA_EVENT_REPORT, MsgSn3 = 79, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), ok = gen_tcp:send(Socket, S3), %% timer:sleep(600), {ok, Packet4} = gen_tcp:recv(Socket, 0, 500), % receive general response GenAckPacket4 = <>, Size4 = size(GenAckPacket4), MsgId4 = ?MS_GENERAL_RESPONSE, MsgSn4 = 2, Header4 = <>, S4 = gen_packet(Header4, GenAckPacket4), ?assertEqual(S4, Packet4), {?JT808_UP_TOPIC, Payload} = receive_msg(), ?assertEqual( #{ <<"header">> => #{ <<"msg_id">> => MsgId3, <<"encrypt">> => ?NO_ENCRYPT, <<"phone">> => <<"000123456789">>, <<"len">> => Size3, <<"msg_sn">> => MsgSn3 }, <<"body">> => #{ <<"id">> => 65, <<"type">> => 2, <<"format">> => 1, <<"event">> => 4, <<"channel">> => 103 } }, emqx_utils_json:decode(Payload, [return_maps]) ), ok = gen_tcp:close(Socket). t_case54_ul_0x0900_send_transparent_data(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, ok = emqx:subscribe(?JT808_UP_TOPIC), % % send event report % MsgBody3 = <<39:8, <<"oufwei">>/binary>>, MsgId3 = ?MC_SEND_TRANSPARENT_DATA, MsgSn3 = 79, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), ok = gen_tcp:send(Socket, S3), %% timer:sleep(600), {ok, Packet4} = gen_tcp:recv(Socket, 0, 500), % Receive general response GenAckPacket4 = <>, Size4 = size(GenAckPacket4), MsgId4 = ?MS_GENERAL_RESPONSE, MsgSn4 = 2, Header4 = <>, S4 = gen_packet(Header4, GenAckPacket4), ?assertEqual(S4, Packet4), {?JT808_UP_TOPIC, Payload} = receive_msg(), ?assertEqual( #{ <<"header">> => #{ <<"msg_id">> => MsgId3, <<"encrypt">> => ?NO_ENCRYPT, <<"phone">> => <<"000123456789">>, <<"len">> => Size3, <<"msg_sn">> => MsgSn3 }, <<"body">> => #{<<"type">> => 39, <<"data">> => base64:encode(<<"oufwei">>)} }, emqx_utils_json:decode(Payload, [return_maps]) ), ok = gen_tcp:close(Socket). t_case55_ul_0x0901_send_zip_data(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, ok = emqx:subscribe(?JT808_UP_TOPIC), % % send event report % MsgBody3 = <<4:?DWORD, <<"1234">>/binary>>, MsgId3 = ?MC_SEND_ZIP_DATA, MsgSn3 = 79, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), ok = gen_tcp:send(Socket, S3), %% timer:sleep(600), {ok, Packet4} = gen_tcp:recv(Socket, 0, 500), % receive general response GenAckPacket4 = <>, Size4 = size(GenAckPacket4), MsgId4 = ?MS_GENERAL_RESPONSE, MsgSn4 = 2, Header4 = <>, S4 = gen_packet(Header4, GenAckPacket4), ?assertEqual(S4, Packet4), {?JT808_UP_TOPIC, Payload} = receive_msg(), ?assertEqual( #{ <<"header">> => #{ <<"msg_id">> => MsgId3, <<"encrypt">> => ?NO_ENCRYPT, <<"phone">> => <<"000123456789">>, <<"len">> => Size3, <<"msg_sn">> => MsgSn3 }, <<"body">> => #{ <<"length">> => 4, <<"data">> => base64:encode(<<"1234">>) } }, emqx_utils_json:decode(Payload, [return_maps]) ), ok = gen_tcp:close(Socket). t_case16_dl_0x8301_set_event(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, DlCommand = #{ <<"header">> => #{<<"msg_id">> => ?MS_SET_EVENT}, <<"body">> => #{ <<"type">> => 3, <<"length">> => 2, <<"events">> => [ #{<<"id">> => 56, <<"length">> => 3, <<"content">> => <<"111">>}, #{<<"id">> => 7, <<"length">> => 5, <<"content">> => <<"nwKdmww">>} ] } }, emqx:publish(emqx_message:make(?JT808_DN_TOPIC, emqx_utils_json:encode(DlCommand))), % % client get downlink command % MsgBody3 = <<3:8, 2:8, 56:8, 3:8, <<"111">>/binary, 7:8, 5:8, <<"nwKdmww">>/binary>>, MsgId3 = ?MS_SET_EVENT, MsgSn3 = 2, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), %% timer:sleep(600), {ok, Packet3} = gen_tcp:recv(Socket, 0, 500), ?LOGT(" S3=~p", [binary_to_hex_string(S3)]), ?LOGT("Packet3=~p", [binary_to_hex_string(Packet3)]), ?assertEqual(S3, Packet3), ?LOGT("client receive command from server ~p", [S3]), client_send_general_response(Socket, MsgId3, MsgSn3, PhoneBCD), % no retrasmition of downlink message %% timer:sleep(10000), {error, timeout} = gen_tcp:recv(Socket, 0, 500), ok = gen_tcp:close(Socket). t_case17_dl_0x8303_set_menu(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, DlCommand = #{ <<"header">> => #{<<"msg_id">> => ?MS_SET_MENU}, <<"body">> => #{ <<"type">> => 3, <<"length">> => 2, <<"menus">> => [ #{<<"type">> => 56, <<"length">> => 3, <<"info">> => <<"111">>}, #{<<"type">> => 7, <<"length">> => 5, <<"info">> => <<"nwKdmww">>} ] } }, emqx:publish(emqx_message:make(?JT808_DN_TOPIC, emqx_utils_json:encode(DlCommand))), %% client get downlink command MsgBody3 = <<3:8, 2:8, 56:8, 3:?WORD, <<"111">>/binary, 7:8, 5:?WORD, <<"nwKdmww">>/binary>>, MsgId3 = ?MS_SET_MENU, MsgSn3 = 2, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), %% timer:sleep(600), {ok, Packet3} = gen_tcp:recv(Socket, 0, 500), ?LOGT(" S3=~p", [binary_to_hex_string(S3)]), ?LOGT("Packet3=~p", [binary_to_hex_string(Packet3)]), ?assertEqual(S3, Packet3), ?LOGT("client receive command from server ~p", [S3]), client_send_general_response(Socket, MsgId3, MsgSn3, PhoneBCD), % no retrasmition of downlink message %% timer:sleep(10000), {error, timeout} = gen_tcp:recv(Socket, 0, 500), ok = gen_tcp:close(Socket). t_case18_dl_0x8304_info_content(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, DlCommand = #{ <<"header">> => #{<<"msg_id">> => ?MS_INFO_CONTENT}, <<"body">> => #{<<"type">> => 3, <<"length">> => 2, <<"info">> => <<"NY">>} }, emqx:publish(emqx_message:make(?JT808_DN_TOPIC, emqx_utils_json:encode(DlCommand))), %% client get downlink command MsgBody3 = <<3:8, 2:?WORD, <<"NY">>/binary>>, MsgId3 = ?MS_INFO_CONTENT, MsgSn3 = 2, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), %% timer:sleep(600), {ok, Packet3} = gen_tcp:recv(Socket, 0, 500), ?LOGT(" S3=~p", [binary_to_hex_string(S3)]), ?LOGT("Packet3=~p", [binary_to_hex_string(Packet3)]), ?assertEqual(S3, Packet3), ?LOGT("client receive command from server ~p", [S3]), client_send_general_response(Socket, MsgId3, MsgSn3, PhoneBCD), % no retrasmition of downlink message %% timer:sleep(10000), {error, timeout} = gen_tcp:recv(Socket, 0, 500), ok = gen_tcp:close(Socket). t_case19_dl_0x8400_phone_callback(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, DlCommand = #{ <<"header">> => #{<<"msg_id">> => ?MS_PHONE_CALLBACK}, <<"body">> => #{<<"type">> => 0, <<"phone">> => <<"15632597856">>} }, emqx:publish(emqx_message:make(?JT808_DN_TOPIC, emqx_utils_json:encode(DlCommand))), %% client get downlink command MsgBody3 = <<0:8, <<"15632597856">>/binary>>, MsgId3 = ?MS_PHONE_CALLBACK, MsgSn3 = 2, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), %% timer:sleep(600), {ok, Packet3} = gen_tcp:recv(Socket, 0, 500), ?LOGT(" S3=~p", [binary_to_hex_string(S3)]), ?LOGT("Packet3=~p", [binary_to_hex_string(Packet3)]), ?assertEqual(S3, Packet3), ?LOGT("client receive command from server ~p", [S3]), client_send_general_response(Socket, MsgId3, MsgSn3, PhoneBCD), % no retrasmition of downlink message %% timer:sleep(10000), {error, timeout} = gen_tcp:recv(Socket, 0, 500), ok = gen_tcp:close(Socket). t_case20_dl_0x8401_set_phone_number(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, DlCommand = #{ <<"header">> => #{<<"msg_id">> => ?MS_SET_PHONE_NUMBER}, <<"body">> => #{ <<"type">> => 2, <<"length">> => 2, <<"contacts">> => [ #{ <<"type">> => 2, <<"phone_len">> => 10, <<"phone">> => <<"13011112222">>, <<"name_len">> => 3, <<"name">> => <<"Tom">> }, #{ <<"type">> => 3, <<"phone_len">> => 11, <<"phone">> => <<"013011113333">>, <<"name_len">> => 4, <<"name">> => <<"Mike">> } ] } }, emqx:publish(emqx_message:make(?JT808_DN_TOPIC, emqx_utils_json:encode(DlCommand))), % % client get downlink command % MsgBody3 = <<2:8, 2:8, 2:8, 10:8, <<"13011112222">>/binary, 3:8, <<"Tom">>/binary, 3:8, 11:8, <<"013011113333">>/binary, 4:8, <<"Mike">>/binary>>, MsgId3 = ?MS_SET_PHONE_NUMBER, MsgSn3 = 2, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), %% timer:sleep(600), {ok, Packet3} = gen_tcp:recv(Socket, 0, 500), ?LOGT(" S3=~p", [binary_to_hex_string(S3)]), ?LOGT("Packet3=~p", [binary_to_hex_string(Packet3)]), ?assertEqual(S3, Packet3), ?LOGT("client receive command from server ~p", [S3]), client_send_general_response(Socket, MsgId3, MsgSn3, PhoneBCD), % no retrasmition of downlink message %% timer:sleep(10000), {error, timeout} = gen_tcp:recv(Socket, 0, 500), ok = gen_tcp:close(Socket). t_case21_dl_0x8600_set_circle_area(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, DlCommand = #{ <<"header">> => #{<<"msg_id">> => ?MS_SET_CIRCLE_AREA}, <<"body">> => #{ <<"type">> => 0, <<"length">> => 2, <<"areas">> => [ #{ <<"id">> => 267, <<"flag">> => 36, <<"center_latitude">> => 20057, <<"center_longitude">> => 4529, <<"radius">> => 279, <<"start_time">> => <<"170912103253">>, <<"end_time">> => <<"170913103253">>, <<"max_speed">> => 120, <<"overspeed_duration">> => 36 }, #{ <<"id">> => 355, <<"flag">> => 36, <<"center_latitude">> => 20057, <<"center_longitude">> => 4529, <<"radius">> => 132, <<"start_time">> => <<"170912103253">>, <<"end_time">> => <<"170913103253">>, <<"max_speed">> => 120, <<"overspeed_duration">> => 36 } ] } }, emqx:publish(emqx_message:make(?JT808_DN_TOPIC, emqx_utils_json:encode(DlCommand))), %% client get downlink command MsgBody3 = <<0:8, 2:8, 267:?DWORD, 36:?WORD, 20057:?DWORD, 4529:?DWORD, 279:?DWORD, <<16#17, 16#09, 16#12, 16#10, 16#32, 16#53>>/binary, <<16#17, 16#09, 16#13, 16#10, 16#32, 16#53>>/binary, 120:?WORD, 36:8, 355:?DWORD, 36:?WORD, 20057:?DWORD, 4529:?DWORD, 132:?DWORD, <<16#17, 16#09, 16#12, 16#10, 16#32, 16#53>>/binary, <<16#17, 16#09, 16#13, 16#10, 16#32, 16#53>>/binary, 120:?WORD, 36:8>>, MsgId3 = ?MS_SET_CIRCLE_AREA, MsgSn3 = 2, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), %% timer:sleep(600), {ok, Packet3} = gen_tcp:recv(Socket, 0, 500), ?LOGT(" S3=~p", [binary_to_hex_string(S3)]), ?LOGT("Packet3=~p", [binary_to_hex_string(Packet3)]), ?assertEqual(S3, Packet3), ?LOGT("client receive command from server ~p", [S3]), client_send_general_response(Socket, MsgId3, MsgSn3, PhoneBCD), % no retrasmition of downlink message %% timer:sleep(10000), {error, timeout} = gen_tcp:recv(Socket, 0, 500), ok = gen_tcp:close(Socket). t_case22_dl_0x8601_del_circle_area(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, DlCommand = #{ <<"header">> => #{<<"msg_id">> => ?MS_DEL_CIRCLE_AREA}, <<"body">> => #{<<"length">> => 2, <<"ids">> => [3, 78]} }, emqx:publish(emqx_message:make(?JT808_DN_TOPIC, emqx_utils_json:encode(DlCommand))), % % client get downlink command % MsgBody3 = <<2:8, 3:?DWORD, 78:?DWORD>>, MsgId3 = ?MS_DEL_CIRCLE_AREA, MsgSn3 = 2, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), %% timer:sleep(600), {ok, Packet3} = gen_tcp:recv(Socket, 0, 500), ?LOGT(" S3=~p", [binary_to_hex_string(S3)]), ?LOGT("Packet3=~p", [binary_to_hex_string(Packet3)]), ?assertEqual(S3, Packet3), ?LOGT("client receive command from server ~p", [S3]), client_send_general_response(Socket, MsgId3, MsgSn3, PhoneBCD), % no retrasmition of downlink message %% timer:sleep(10000), {error, timeout} = gen_tcp:recv(Socket, 0, 500), ok = gen_tcp:close(Socket). t_case23_dl_0x8602_set_rect_area(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, DlCommand = #{ <<"header">> => #{<<"msg_id">> => ?MS_SET_RECT_AREA}, <<"body">> => #{ <<"type">> => 0, <<"length">> => 2, <<"areas">> => [ #{ <<"id">> => 267, <<"flag">> => 36, <<"lt_lat">> => 20057, <<"lt_lng">> => 4529, <<"rb_lat">> => 30057, <<"rb_lng">> => 5529, <<"start_time">> => <<"170912103253">>, <<"end_time">> => <<"170913103253">>, <<"max_speed">> => 120, <<"overspeed_duration">> => 36 }, #{ <<"id">> => 355, <<"flag">> => 36, <<"lt_lat">> => 20057, <<"lt_lng">> => 4529, <<"rb_lat">> => 30057, <<"rb_lng">> => 5529, <<"start_time">> => <<"170912103253">>, <<"end_time">> => <<"170913103253">>, <<"max_speed">> => 120, <<"overspeed_duration">> => 36 } ] } }, emqx:publish(emqx_message:make(?JT808_DN_TOPIC, emqx_utils_json:encode(DlCommand))), % % client get downlink command % MsgBody3 = <<0:8, 2:8, 267:?DWORD, 36:?WORD, 20057:?DWORD, 4529:?DWORD, 30057:?DWORD, 5529:?DWORD, <<16#17, 16#09, 16#12, 16#10, 16#32, 16#53>>/binary, <<16#17, 16#09, 16#13, 16#10, 16#32, 16#53>>/binary, 120:?WORD, 36:8, 355:?DWORD, 36:?WORD, 20057:?DWORD, 4529:?DWORD, 30057:?DWORD, 5529:?DWORD, <<16#17, 16#09, 16#12, 16#10, 16#32, 16#53>>/binary, <<16#17, 16#09, 16#13, 16#10, 16#32, 16#53>>/binary, 120:?WORD, 36:8>>, MsgId3 = ?MS_SET_RECT_AREA, MsgSn3 = 2, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), %% timer:sleep(600), {ok, Packet3} = gen_tcp:recv(Socket, 0, 500), ?LOGT(" S3=~p", [binary_to_hex_string(S3)]), ?LOGT("Packet3=~p", [binary_to_hex_string(Packet3)]), ?assertEqual(S3, Packet3), ?LOGT("client receive command from server ~p", [S3]), client_send_general_response(Socket, MsgId3, MsgSn3, PhoneBCD), % no retrasmition of downlink message %% timer:sleep(10000), {error, timeout} = gen_tcp:recv(Socket, 0, 500), ok = gen_tcp:close(Socket). t_case24_dl_0x8603_del_circle_area(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, DlCommand = #{ <<"header">> => #{<<"msg_id">> => ?MS_DEL_RECT_AREA}, <<"body">> => #{<<"length">> => 2, <<"ids">> => [3, 78]} }, emqx:publish(emqx_message:make(?JT808_DN_TOPIC, emqx_utils_json:encode(DlCommand))), % % client get downlink command % MsgBody3 = <<2:8, 3:?DWORD, 78:?DWORD>>, MsgId3 = ?MS_DEL_RECT_AREA, MsgSn3 = 2, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), %% timer:sleep(600), {ok, Packet3} = gen_tcp:recv(Socket, 0, 500), ?LOGT(" S3=~p", [binary_to_hex_string(S3)]), ?LOGT("Packet3=~p", [binary_to_hex_string(Packet3)]), ?assertEqual(S3, Packet3), ?LOGT("client receive command from server ~p", [S3]), client_send_general_response(Socket, MsgId3, MsgSn3, PhoneBCD), % no retrasmition of downlink message %% timer:sleep(10000), {error, timeout} = gen_tcp:recv(Socket, 0, 500), ok = gen_tcp:close(Socket). t_case25_dl_0x8604_set_poly_area(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, DlCommand = #{ <<"header">> => #{<<"msg_id">> => ?MS_SET_POLY_AREA}, <<"body">> => #{ <<"id">> => 267, <<"flag">> => 36, <<"start_time">> => <<"170912103253">>, <<"end_time">> => <<"170913103253">>, <<"max_speed">> => 120, <<"overspeed_duration">> => 36, <<"length">> => 3, <<"points">> => [ #{<<"lat">> => 20057, <<"lng">> => 4529}, #{<<"lat">> => 21057, <<"lng">> => 14569}, #{<<"lat">> => 7032, <<"lng">> => 429} ] } }, emqx:publish(emqx_message:make(?JT808_DN_TOPIC, emqx_utils_json:encode(DlCommand))), % % client get downlink command % MsgBody3 = <<267:?DWORD, 36:?WORD, <<16#17, 16#09, 16#12, 16#10, 16#32, 16#53>>/binary, <<16#17, 16#09, 16#13, 16#10, 16#32, 16#53>>/binary, 120:?WORD, 36:8, 3:?WORD, 20057:?DWORD, 4529:?DWORD, 21057:?DWORD, 14569:?DWORD, 7032:?DWORD, 429:?DWORD>>, MsgId3 = ?MS_SET_POLY_AREA, MsgSn3 = 2, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), %% timer:sleep(600), {ok, Packet3} = gen_tcp:recv(Socket, 0, 500), ?LOGT(" S3=~p", [binary_to_hex_string(S3)]), ?LOGT("Packet3=~p", [binary_to_hex_string(Packet3)]), ?assertEqual(S3, Packet3), ?LOGT("client receive command from server ~p", [S3]), client_send_general_response(Socket, MsgId3, MsgSn3, PhoneBCD), % no retrasmition of downlink message %% timer:sleep(10000), {error, timeout} = gen_tcp:recv(Socket, 0, 500), ok = gen_tcp:close(Socket). t_case26_dl_0x8605_del_poly_area(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, DlCommand = #{ <<"header">> => #{<<"msg_id">> => ?MS_DEL_POLY_AREA}, <<"body">> => #{<<"length">> => 2, <<"ids">> => [3, 78]} }, emqx:publish(emqx_message:make(?JT808_DN_TOPIC, emqx_utils_json:encode(DlCommand))), % % client get downlink command % MsgBody3 = <<2:8, 3:?DWORD, 78:?DWORD>>, MsgId3 = ?MS_DEL_POLY_AREA, MsgSn3 = 2, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), %% timer:sleep(600), {ok, Packet3} = gen_tcp:recv(Socket, 0, 500), ?LOGT(" S3=~p", [binary_to_hex_string(S3)]), ?LOGT("Packet3=~p", [binary_to_hex_string(Packet3)]), ?assertEqual(S3, Packet3), ?LOGT("client receive command from server ~p", [S3]), client_send_general_response(Socket, MsgId3, MsgSn3, PhoneBCD), % no retrasmition of downlink message %% timer:sleep(10000), {error, timeout} = gen_tcp:recv(Socket, 0, 500), ok = gen_tcp:close(Socket). t_case27_dl_0x8606_set_path(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, DlCommand = #{ <<"header">> => #{<<"msg_id">> => ?MS_SET_PATH}, <<"body">> => #{ <<"id">> => 267, <<"flag">> => 36, <<"start_time">> => <<"170912103253">>, <<"end_time">> => <<"170913103253">>, <<"length">> => 2, <<"points">> => [ #{ <<"point_id">> => 3, <<"path_id">> => 71, <<"point_lat">> => 7324, <<"point_lng">> => 9732, <<"width">> => 54, <<"attrib">> => 23, <<"passed">> => 0, <<"uncovered">> => 1, <<"max_speed">> => 132, <<"overspeed_duration">> => 4 }, #{ <<"point_id">> => 4, <<"path_id">> => 72, <<"point_lat">> => 7324, <<"point_lng">> => 9732, <<"width">> => 54, <<"attrib">> => 23, <<"passed">> => 0, <<"uncovered">> => 1, <<"max_speed">> => 169, <<"overspeed_duration">> => 69 } ] } }, emqx:publish(emqx_message:make(?JT808_DN_TOPIC, emqx_utils_json:encode(DlCommand))), % % client get downlink command % MsgBody3 = <<267:?DWORD, 36:?WORD, <<16#17, 16#09, 16#12, 16#10, 16#32, 16#53>>/binary, <<16#17, 16#09, 16#13, 16#10, 16#32, 16#53>>/binary, 2:?WORD, 3:?DWORD, 71:?DWORD, 7324:?DWORD, 9732:?DWORD, 54:8, 23:8, 0:?WORD, 1:?WORD, 132:?WORD, 4:8, 4:?DWORD, 72:?DWORD, 7324:?DWORD, 9732:?DWORD, 54:8, 23:8, 0:?WORD, 1:?WORD, 169:?WORD, 69:8>>, MsgId3 = ?MS_SET_PATH, MsgSn3 = 2, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), %% timer:sleep(600), {ok, Packet3} = gen_tcp:recv(Socket, 0, 500), ?LOGT(" S3=~p", [binary_to_hex_string(S3)]), ?LOGT("Packet3=~p", [binary_to_hex_string(Packet3)]), ?assertEqual(S3, Packet3), ?LOGT("client receive command from server ~p", [S3]), client_send_general_response(Socket, MsgId3, MsgSn3, PhoneBCD), % no retrasmition of downlink message %% timer:sleep(10000), {error, timeout} = gen_tcp:recv(Socket, 0, 500), ok = gen_tcp:close(Socket). t_case26_dl_0x8607_del_path(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, DlCommand = #{ <<"header">> => #{<<"msg_id">> => ?MS_DEL_PATH}, <<"body">> => #{<<"length">> => 2, <<"ids">> => [3, 78]} }, emqx:publish(emqx_message:make(?JT808_DN_TOPIC, emqx_utils_json:encode(DlCommand))), % % client get downlink command % MsgBody3 = <<2:8, 3:?DWORD, 78:?DWORD>>, MsgId3 = ?MS_DEL_PATH, MsgSn3 = 2, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), %% timer:sleep(600), {ok, Packet3} = gen_tcp:recv(Socket, 0, 500), ?LOGT(" S3=~p", [binary_to_hex_string(S3)]), ?LOGT("Packet3=~p", [binary_to_hex_string(Packet3)]), ?assertEqual(S3, Packet3), ?LOGT("client receive command from server ~p", [S3]), client_send_general_response(Socket, MsgId3, MsgSn3, PhoneBCD), % no retrasmition of downlink message %% timer:sleep(10000), {error, timeout} = gen_tcp:recv(Socket, 0, 500), ok = gen_tcp:close(Socket). t_case27_dl_0x8700_drive_record_capture(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, ok = emqx:subscribe(?JT808_UP_TOPIC), CaptureCmd = 2, DlCommand = #{ <<"header">> => #{<<"msg_id">> => ?MS_DRIVE_RECORD_CAPTURE}, <<"body">> => #{ <<"command">> => CaptureCmd, <<"param">> => base64:encode(<<"000123456789">>) } }, emqx:publish(emqx_message:make(?JT808_DN_TOPIC, emqx_utils_json:encode(DlCommand))), % % client get downlink command % MsgBody3 = <<2:8, <<"000123456789">>/binary>>, MsgId3 = ?MS_DRIVE_RECORD_CAPTURE, MsgSn3 = 2, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), %% timer:sleep(600), {ok, Packet3} = gen_tcp:recv(Socket, 0, 500), ?LOGT(" S3=~p", [binary_to_hex_string(S3)]), ?LOGT("Packet3=~p", [binary_to_hex_string(Packet3)]), ?assertEqual(S3, Packet3), ?LOGT("client receive command from server ~p", [S3]), % client send "drive record report" UlPacket4 = <>/binary>>, Size4 = size(UlPacket4), MsgId4 = ?MC_DRIVE_RECORD_REPORT, MsgSn4 = 2, Header4 = <>, S4 = gen_packet(Header4, UlPacket4), ?LOGT("S4 = ~p", [S4]), ok = gen_tcp:send(Socket, S4), timer:sleep(100), {?JT808_UP_TOPIC, Payload} = receive_msg(), ?assertEqual( #{ <<"header">> => #{ <<"encrypt">> => 0, <<"len">> => Size4, <<"msg_id">> => ?MC_DRIVE_RECORD_REPORT, <<"msg_sn">> => 2, <<"phone">> => <<"000123456789">> }, <<"body">> => #{ <<"seq">> => MsgSn3, <<"command">> => CaptureCmd, <<"data">> => base64:encode(<<"77777">>) } }, emqx_utils_json:decode(Payload, [return_maps]) ), % no retrasmition of downlink message {error, timeout} = gen_tcp:recv(Socket, 0, 500), ok = gen_tcp:close(Socket). t_case28_dl_0x8701_drive_record_param_send(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, CaptureCmd = 2, DlCommand = #{ <<"header">> => #{<<"msg_id">> => ?MS_DRIVE_REC_PARAM_SEND}, <<"body">> => #{ <<"command">> => CaptureCmd, <<"param">> => base64:encode(<<"000123456789">>) } }, emqx:publish(emqx_message:make(?JT808_DN_TOPIC, emqx_utils_json:encode(DlCommand))), % % client get downlink command % MsgBody3 = <>/binary>>, MsgId3 = ?MS_DRIVE_REC_PARAM_SEND, MsgSn3 = 2, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), %% timer:sleep(600), {ok, Packet3} = gen_tcp:recv(Socket, 0, 500), ?LOGT(" S3=~p", [binary_to_hex_string(S3)]), ?LOGT("Packet3=~p", [binary_to_hex_string(Packet3)]), ?assertEqual(S3, Packet3), ?LOGT("client receive command from server ~p", [S3]), client_send_general_response(Socket, MsgId3, MsgSn3, PhoneBCD), % no retrasmition of downlink message %% timer:sleep(10000), {error, timeout} = gen_tcp:recv(Socket, 0, 500), ok = gen_tcp:close(Socket). t_case29_dl_0x8702_request_driver_id(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, ok = emqx:subscribe(?JT808_UP_TOPIC), DlCommand = #{<<"header">> => #{<<"msg_id">> => ?MS_REQ_DRIVER_ID}}, emqx:publish(emqx_message:make(?JT808_DN_TOPIC, emqx_utils_json:encode(DlCommand))), % % client get downlink command % MsgBody3 = <<>>, MsgId3 = ?MS_REQ_DRIVER_ID, MsgSn3 = 2, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), %% timer:sleep(600), {ok, Packet3} = gen_tcp:recv(Socket, 0, 500), ?LOGT(" S3=~p", [binary_to_hex_string(S3)]), ?LOGT("Packet3=~p", [binary_to_hex_string(Packet3)]), ?assertEqual(S3, Packet3), ?LOGT("client receive command from server ~p", [S3]), % client send "drive record report" UlPacket4 = <<1:8, 16#17, 16#10, 16#12, 16#09, 16#03, 16#52, 0:8, 3:8, <<"Tom">>/binary, <<"77778888999900001111">>/binary, 6:8, <<"org123">>/binary, 16#20, 16#30, 16#12, 16#31>>, Size4 = size(UlPacket4), MsgId4 = ?MC_DRIVER_ID_REPORT, MsgSn4 = 2, Header4 = <>, S4 = gen_packet(Header4, UlPacket4), ?LOGT("S4 = ~p", [S4]), ok = gen_tcp:send(Socket, S4), timer:sleep(100), {?JT808_UP_TOPIC, Payload} = receive_msg(), ?assertEqual( #{ <<"header">> => #{ <<"encrypt">> => 0, <<"len">> => Size4, <<"msg_id">> => ?MC_DRIVER_ID_REPORT, <<"msg_sn">> => 2, <<"phone">> => <<"000123456789">> }, <<"body">> => #{ <<"status">> => 1, <<"time">> => <<"171012090352">>, <<"ic_result">> => 0, <<"driver_name">> => <<"Tom">>, <<"certificate">> => <<"77778888999900001111">>, <<"organization">> => <<"org123">>, <<"cert_expiry">> => <<"20301231">> } }, emqx_utils_json:decode(Payload, [return_maps]) ), % no retrasmition of downlink message %% timer:sleep(10000), {error, timeout} = gen_tcp:recv(Socket, 0, 500), ok = gen_tcp:close(Socket). t_case30_dl_0x8801_camera_shot(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, ok = emqx:subscribe(?JT808_UP_TOPIC), DlCommand = #{ <<"header">> => #{<<"msg_id">> => ?MS_CAMERA_SHOT}, <<"body">> => #{ <<"channel_id">> => 172, <<"command">> => 5, <<"period">> => 2, <<"save">> => 1, <<"resolution">> => 8, <<"quality">> => 3, <<"bright">> => 4, <<"contrast">> => 5, <<"saturate">> => 6, <<"chromaticity">> => 7 } }, emqx:publish(emqx_message:make(?JT808_DN_TOPIC, emqx_utils_json:encode(DlCommand))), % % client get downlink command % MsgBody3 = <<172:8, 5:?WORD, 2:?WORD, 1:8, 8:8, 3:8, 4:8, 5:8, 6:8, 7:8>>, MsgId3 = ?MS_CAMERA_SHOT, MsgSn3 = 2, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), %% timer:sleep(600), {ok, Packet3} = gen_tcp:recv(Socket, 0, 500), ?LOGT(" S3=~p", [binary_to_hex_string(S3)]), ?LOGT("Packet3=~p", [binary_to_hex_string(Packet3)]), ?assertEqual(S3, Packet3), ?LOGT("client receive command from server ~p", [S3]), % client send "camera shot ack" UlPacket4 = <>, Size4 = size(UlPacket4), MsgId4 = ?MC_CAMERA_SHOT_ACK, MsgSn4 = 2, Header4 = <>, S4 = gen_packet(Header4, UlPacket4), ?LOGT("S4 = ~p", [S4]), ok = gen_tcp:send(Socket, S4), timer:sleep(100), {?JT808_UP_TOPIC, Payload} = receive_msg(), ?assertEqual( #{ <<"header">> => #{ <<"encrypt">> => 0, <<"len">> => Size4, <<"msg_id">> => ?MC_CAMERA_SHOT_ACK, <<"msg_sn">> => 2, <<"phone">> => <<"000123456789">> }, <<"body">> => #{ <<"seq">> => MsgSn3, <<"result">> => 0, <<"length">> => 2, <<"ids">> => [220, 221] } }, emqx_utils_json:decode(Payload, [return_maps]) ), % No retrasmition of downlink message %% timer:sleep(10000), {error, timeout} = gen_tcp:recv(Socket, 0, 500), ok = gen_tcp:close(Socket). t_case31_dl_0x8802_mm_data_search(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, ok = emqx:subscribe(?JT808_UP_TOPIC), DlCommand = #{ <<"header">> => #{<<"msg_id">> => ?MS_MM_DATA_SEARCH}, <<"body">> => #{ <<"type">> => 0, <<"channel">> => 17, <<"event">> => 2, <<"start_time">> => <<"170923144607">>, <<"end_time">> => <<"170923145826">> } }, emqx:publish(emqx_message:make(?JT808_DN_TOPIC, emqx_utils_json:encode(DlCommand))), % % client get downlink command % MsgBody3 = <<0:8, 17:8, 2:8, 16#17, 16#09, 16#23, 16#14, 16#46, 16#07, 16#17, 16#09, 16#23, 16#14, 16#58, 16#26>>, MsgId3 = ?MS_MM_DATA_SEARCH, MsgSn3 = 2, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), %% timer:sleep(600), {ok, Packet3} = gen_tcp:recv(Socket, 0, 500), ?LOGT(" S3=~p", [binary_to_hex_string(S3)]), ?LOGT("Packet3=~p", [binary_to_hex_string(Packet3)]), ?assertEqual(S3, Packet3), ?LOGT("client receive command from server ~p", [S3]), % client send "mm data search ack" {LocBin, LocJson} = location_report_28bytes(), UlPacket4 = <>, Size4 = size(UlPacket4), MsgId4 = ?MC_MM_DATA_SEARCH_ACK, MsgSn4 = 2, Header4 = <>, S4 = gen_packet(Header4, UlPacket4), ?LOGT("S4 = ~p", [S4]), ok = gen_tcp:send(Socket, S4), timer:sleep(100), {?JT808_UP_TOPIC, Payload} = receive_msg(), ?assertEqual( #{ <<"header">> => #{ <<"encrypt">> => 0, <<"len">> => Size4, <<"msg_id">> => ?MC_MM_DATA_SEARCH_ACK, <<"msg_sn">> => 2, <<"phone">> => <<"000123456789">> }, <<"body">> => #{ <<"seq">> => MsgSn3, <<"length">> => 2, <<"result">> => [ #{ <<"id">> => 25, <<"type">> => 1, <<"channel">> => 97, <<"event">> => 1, <<"location">> => LocJson }, #{ <<"id">> => 26, <<"type">> => 2, <<"channel">> => 98, <<"event">> => 3, <<"location">> => LocJson } ] } }, emqx_utils_json:decode(Payload, [return_maps]) ), %% No retrasmition of downlink message {error, timeout} = gen_tcp:recv(Socket, 0, 500), ok = gen_tcp:close(Socket). t_case32_dl_0x8803_mm_data_upload(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, DlCommand = #{ <<"header">> => #{<<"msg_id">> => ?MS_MM_DATA_UPLOAD}, <<"body">> => #{ <<"type">> => 0, <<"channel">> => 17, <<"event">> => 2, <<"start_time">> => <<"170923144607">>, <<"end_time">> => <<"170923145826">>, <<"delete">> => 1 } }, emqx:publish(emqx_message:make(?JT808_DN_TOPIC, emqx_utils_json:encode(DlCommand))), % % client get downlink command % MsgBody3 = <<0:8, 17:8, 2:8, 16#17, 16#09, 16#23, 16#14, 16#46, 16#07, 16#17, 16#09, 16#23, 16#14, 16#58, 16#26, 1:8>>, MsgId3 = ?MS_MM_DATA_UPLOAD, MsgSn3 = 2, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), %% timer:sleep(600), {ok, Packet3} = gen_tcp:recv(Socket, 0, 500), ?LOGT(" S3=~p", [binary_to_hex_string(S3)]), ?LOGT("Packet3=~p", [binary_to_hex_string(Packet3)]), ?assertEqual(S3, Packet3), ?LOGT("client receive command from server ~p", [S3]), client_send_general_response(Socket, MsgId3, MsgSn3, PhoneBCD), % no retrasmition of downlink message %% timer:sleep(10000), {error, timeout} = gen_tcp:recv(Socket, 0, 500), ok = gen_tcp:close(Socket). t_case33_dl_0x8804_voice_record(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, DlCommand = #{ <<"header">> => #{<<"msg_id">> => ?MS_VOICE_RECORD}, <<"body">> => #{ <<"command">> => 1, <<"time">> => 2, <<"save">> => 3, <<"rate">> => 4 } }, emqx:publish(emqx_message:make(?JT808_DN_TOPIC, emqx_utils_json:encode(DlCommand))), % % client get downlink command % MsgBody3 = <<1:8, 2:?WORD, 3:8, 4:8>>, MsgId3 = ?MS_VOICE_RECORD, MsgSn3 = 2, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), %% timer:sleep(600), {ok, Packet3} = gen_tcp:recv(Socket, 0, 500), ?LOGT(" S3=~p", [binary_to_hex_string(S3)]), ?LOGT("Packet3=~p", [binary_to_hex_string(Packet3)]), ?assertEqual(S3, Packet3), ?LOGT("client receive command from server ~p", [S3]), client_send_general_response(Socket, MsgId3, MsgSn3, PhoneBCD), % no retrasmition of downlink message %% timer:sleep(10000), {error, timeout} = gen_tcp:recv(Socket, 0, 500), ok = gen_tcp:close(Socket). t_case34_dl_0x8805_single_mm_data_ctrl(_Config) -> {ok, Socket} = gen_tcp:connect({127, 0, 0, 1}, ?PORT, [binary, {active, false}]), {ok, AuthCode} = client_regi_procedure(Socket), ok = client_auth_procedure(Socket, AuthCode), PhoneBCD = <<16#00, 16#01, 16#23, 16#45, 16#67, 16#89>>, ok = emqx:subscribe(?JT808_UP_TOPIC), DlCommand = #{ <<"header">> => #{<<"msg_id">> => ?MS_SINGLE_MM_DATA_CTRL}, <<"body">> => #{ <<"id">> => 30, <<"flag">> => 40 } }, emqx:publish(emqx_message:make(?JT808_DN_TOPIC, emqx_utils_json:encode(DlCommand))), %% client get downlink command MsgBody3 = <<30:?DWORD, 40:8>>, MsgId3 = ?MS_SINGLE_MM_DATA_CTRL, MsgSn3 = 2, Size3 = size(MsgBody3), Header3 = <>, S3 = gen_packet(Header3, MsgBody3), %% timer:sleep(600), {ok, Packet3} = gen_tcp:recv(Socket, 0, 500), ?LOGT(" S3=~p", [binary_to_hex_string(S3)]), ?LOGT("Packet3=~p", [binary_to_hex_string(Packet3)]), ?assertEqual(S3, Packet3), ?LOGT("client receive command from server ~p", [S3]), {LocBin, LocJson} = location_report_28bytes(), UlPacket4 = <>, Size4 = size(UlPacket4), MsgId4 = ?MC_MM_DATA_SEARCH_ACK, MsgSn4 = 2, Header4 = <>, S4 = gen_packet(Header4, UlPacket4), ?LOGT("S4 = ~p", [S4]), ok = gen_tcp:send(Socket, S4), timer:sleep(100), {?JT808_UP_TOPIC, Payload} = receive_msg(), ?assertEqual( #{ <<"header">> => #{ <<"encrypt">> => 0, <<"len">> => Size4, <<"msg_id">> => ?MC_MM_DATA_SEARCH_ACK, <<"msg_sn">> => 2, <<"phone">> => <<"000123456789">> }, <<"body">> => #{ <<"seq">> => MsgSn3, <<"length">> => 2, <<"result">> => [ #{ <<"id">> => 25, <<"type">> => 1, <<"channel">> => 97, <<"event">> => 1, <<"location">> => LocJson }, #{ <<"id">> => 26, <<"type">> => 2, <<"channel">> => 98, <<"event">> => 3, <<"location">> => LocJson } ] } }, emqx_utils_json:decode(Payload, [return_maps]) ), % no retrasmition of downlink message %%timer:sleep(10000), {error, timeout} = gen_tcp:recv(Socket, 0, 500), ok = gen_tcp:close(Socket). t_create_ALLOW_invalid_auth_config(_Config) -> test_invalid_config(create, true). t_create_DISALLOW_invalid_auth_config(_Config) -> test_invalid_config(create, false). t_update_ALLOW_invalid_auth_config(_Config) -> test_invalid_config(update, true). t_update_DISALLOW_invalid_auth_config(_Config) -> test_invalid_config(update, false). test_invalid_config(CreateOrUpdate, AnonymousAllowed) -> InvalidConfig = raw_jt808_config(AnonymousAllowed), UpdateResult = create_or_update(CreateOrUpdate, InvalidConfig), ?assertMatch( {error, #{ kind := validation_error, reason := matched_no_union_member, path := "gateway.jt808.proto.auth" }}, UpdateResult ). create_or_update(create, InvalidConfig) -> emqx_gateway_conf:load_gateway(jt808, InvalidConfig); create_or_update(update, InvalidConfig) -> emqx_gateway_conf:update_gateway(jt808, InvalidConfig). %% Allow: allow anonymous connection, registry and authentication URL not required. raw_jt808_config(Allow = true) -> AuthConfig = #{ <<"auth">> => #{ <<"allow_anonymous">> => Allow, %% registry and authentication `NOT REQUIRED`, but can be configured <<"registry">> => <>, <<"authentication">> => <>, <<"BADKEY_registry_url">> => <> } }, emqx_utils_maps:deep_merge(raw_jt808_config(), #{<<"proto">> => AuthConfig}); %% DisAllow: required registry and authentication URL configuration to auth client. raw_jt808_config(DisAllow = false) -> AuthConfig = #{ <<"auth">> => #{ <<"allow_anonymous">> => DisAllow %% registry and authentication are required but missed here %% %% <<"registry">> => <>, %% <<"authentication">> => <> } }, emqx_utils_maps:deep_merge(raw_jt808_config(), #{<<"proto">> => AuthConfig}). raw_jt808_config() -> #{ <<"enable">> => true, <<"enable_stats">> => true, <<"frame">> => #{<<"max_length">> => 8192}, <<"idle_timeout">> => <<"30s">>, <<"max_retry_times">> => 3, <<"message_queue_len">> => 10, <<"mountpoint">> => <<"jt808/${clientid}/">>, <<"proto">> => #{ <<"dn_topic">> => <<"jt808/${clientid}/${phone}/dn">>, <<"up_topic">> => <<"jt808/${clientid}/${phone}/up">> }, <<"retry_interval">> => <<"8s">> }.