fix(lwm2m): write incorrect integer to device (#5425)
* fix(test): add testcase for write integer values * fix(lwm2m): write incorrect integer to device * fix(emqx_lwm2m): refactor the code for getting bits len of a signed int * chore(emqx_lwm2m): bump version for emqx_lwm2m to 4.3.3
This commit is contained in:
parent
ff96250b0b
commit
c09cb64db6
|
@ -1,6 +1,6 @@
|
||||||
{application,emqx_lwm2m,
|
{application,emqx_lwm2m,
|
||||||
[{description,"EMQ X LwM2M Gateway"},
|
[{description,"EMQ X LwM2M Gateway"},
|
||||||
{vsn, "4.3.2"}, % strict semver, bump manually!
|
{vsn, "4.3.3"}, % strict semver, bump manually!
|
||||||
{modules,[]},
|
{modules,[]},
|
||||||
{registered,[emqx_lwm2m_sup]},
|
{registered,[emqx_lwm2m_sup]},
|
||||||
{applications,[kernel,stdlib,lwm2m_coap]},
|
{applications,[kernel,stdlib,lwm2m_coap]},
|
||||||
|
|
|
@ -1,13 +1,19 @@
|
||||||
%% -*-: erlang -*-
|
%% -*-: erlang -*-
|
||||||
{VSN,
|
{"4.3.3",
|
||||||
[
|
[
|
||||||
{<<"4.3.[0-1]">>, [
|
{<<"4.3.[0-1]">>, [
|
||||||
{restart_application, emqx_lwm2m}
|
{restart_application, emqx_lwm2m}
|
||||||
|
]},
|
||||||
|
{"4.3.2", [
|
||||||
|
{load_module, emqx_lwm2m_message, brutal_purge, soft_purge, []}
|
||||||
]}
|
]}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{<<"4.3.[0-1]">>, [
|
{<<"4.3.[0-1]">>, [
|
||||||
{restart_application, emqx_lwm2m}
|
{restart_application, emqx_lwm2m}
|
||||||
|
]},
|
||||||
|
{"4.3.2", [
|
||||||
|
{load_module, emqx_lwm2m_message, brutal_purge, soft_purge, []}
|
||||||
]}
|
]}
|
||||||
]
|
]
|
||||||
}.
|
}.
|
||||||
|
|
|
@ -22,6 +22,9 @@
|
||||||
, opaque_to_json/2
|
, opaque_to_json/2
|
||||||
, translate_json/1
|
, translate_json/1
|
||||||
]).
|
]).
|
||||||
|
-ifdef(TEST).
|
||||||
|
-export([ bits/1 ]).
|
||||||
|
-endif.
|
||||||
|
|
||||||
-include("emqx_lwm2m.hrl").
|
-include("emqx_lwm2m.hrl").
|
||||||
|
|
||||||
|
@ -364,23 +367,6 @@ encode_number(Int) when is_integer(Int) ->
|
||||||
encode_number(Float) when is_float(Float) ->
|
encode_number(Float) when is_float(Float) ->
|
||||||
<<Float:64/float>>.
|
<<Float:64/float>>.
|
||||||
|
|
||||||
encode_int(Int) when Int >= 0 ->
|
|
||||||
binary:encode_unsigned(Int);
|
|
||||||
encode_int(Int) when Int < 0 ->
|
|
||||||
Size = byte_size_of_signed(-Int) * 8,
|
|
||||||
<<Int:Size/signed>>.
|
|
||||||
|
|
||||||
byte_size_of_signed(UInt) ->
|
|
||||||
byte_size_of_signed(UInt, 0).
|
|
||||||
|
|
||||||
byte_size_of_signed(UInt, N) ->
|
|
||||||
BitSize = (8*N - 1),
|
|
||||||
Max = (1 bsl BitSize),
|
|
||||||
if
|
|
||||||
UInt =< Max -> N;
|
|
||||||
UInt > Max -> byte_size_of_signed(UInt, N+1)
|
|
||||||
end.
|
|
||||||
|
|
||||||
binary_to_number(NumStr) ->
|
binary_to_number(NumStr) ->
|
||||||
try
|
try
|
||||||
binary_to_integer(NumStr)
|
binary_to_integer(NumStr)
|
||||||
|
@ -388,3 +374,26 @@ binary_to_number(NumStr) ->
|
||||||
error:badarg ->
|
error:badarg ->
|
||||||
binary_to_float(NumStr)
|
binary_to_float(NumStr)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
encode_int(Int) ->
|
||||||
|
Bits = bits(Int),
|
||||||
|
<<Int:Bits/signed>>.
|
||||||
|
|
||||||
|
bits(I) when I < 0 -> bits_neg(I);
|
||||||
|
bits(I) -> bits_pos(I).
|
||||||
|
|
||||||
|
%% Quote:
|
||||||
|
%% Integer: An 8, 16, 32 or 64-bit signed integer.
|
||||||
|
%% The valid range of the value for a Resource SHOULD be defined.
|
||||||
|
%% This data type is also used for the purpose of enumeration.
|
||||||
|
%%
|
||||||
|
%% NOTE: Integer should not be encoded to 24-bits, 40-bits, etc.
|
||||||
|
bits_pos(I) when I < (1 bsl 7) -> 8;
|
||||||
|
bits_pos(I) when I < (1 bsl 15) -> 16;
|
||||||
|
bits_pos(I) when I < (1 bsl 31) -> 32;
|
||||||
|
bits_pos(I) when I < (1 bsl 63) -> 64.
|
||||||
|
|
||||||
|
bits_neg(I) when I >= -((1 bsl 7)) -> 8;
|
||||||
|
bits_neg(I) when I >= -((1 bsl 15)) -> 16;
|
||||||
|
bits_neg(I) when I >= -((1 bsl 31)) -> 32;
|
||||||
|
bits_neg(I) when I >= -((1 bsl 63)) -> 64.
|
||||||
|
|
|
@ -41,6 +41,7 @@ all() ->
|
||||||
, {group, test_grp_5_write_attr}
|
, {group, test_grp_5_write_attr}
|
||||||
, {group, test_grp_6_observe}
|
, {group, test_grp_6_observe}
|
||||||
, {group, test_grp_8_object_19}
|
, {group, test_grp_8_object_19}
|
||||||
|
, {group, test_grp_bugs}
|
||||||
].
|
].
|
||||||
|
|
||||||
suite() -> [{timetrap, {seconds, 90}}].
|
suite() -> [{timetrap, {seconds, 90}}].
|
||||||
|
@ -106,6 +107,9 @@ groups() ->
|
||||||
{test_grp_9_psm_queue_mode, [RepeatOpt], [
|
{test_grp_9_psm_queue_mode, [RepeatOpt], [
|
||||||
case90_psm_mode,
|
case90_psm_mode,
|
||||||
case90_queue_mode
|
case90_queue_mode
|
||||||
|
]},
|
||||||
|
{test_grp_bugs, [RepeatOpt], [
|
||||||
|
case_bug_emqx_4989
|
||||||
]}
|
]}
|
||||||
].
|
].
|
||||||
|
|
||||||
|
@ -145,6 +149,56 @@ end_per_testcase(_AllTestCase, Config) ->
|
||||||
%% Cases
|
%% Cases
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
|
case_bug_emqx_4989(Config) ->
|
||||||
|
%% https://github.com/emqx/emqx/issues/4989
|
||||||
|
% step 1, device register ...
|
||||||
|
Epn = "urn:oma:lwm2m:oma:3",
|
||||||
|
MsgId1 = 15,
|
||||||
|
UdpSock = ?config(sock, Config),
|
||||||
|
ObjectList = <<"</1>, </2>, </3/0>, </4>, </5>">>,
|
||||||
|
RespTopic = list_to_binary("lwm2m/"++Epn++"/up/resp"),
|
||||||
|
emqtt:subscribe(?config(emqx_c, Config), RespTopic, qos0),
|
||||||
|
timer:sleep(200),
|
||||||
|
|
||||||
|
std_register(UdpSock, Epn, ObjectList, MsgId1, RespTopic),
|
||||||
|
|
||||||
|
% step2, send a WRITE command to device
|
||||||
|
CommandTopic = <<"lwm2m/", (list_to_binary(Epn))/binary, "/dn/dm">>,
|
||||||
|
CmdId = 307,
|
||||||
|
Command = #{<<"requestID">> => CmdId, <<"cacheID">> => CmdId,
|
||||||
|
<<"msgType">> => <<"write">>,
|
||||||
|
<<"data">> => #{
|
||||||
|
<<"path">> => <<"/1/0/2">>,
|
||||||
|
<<"type">> => <<"Integer">>,
|
||||||
|
<<"value">> => 129
|
||||||
|
}
|
||||||
|
},
|
||||||
|
CommandJson = emqx_json:encode(Command),
|
||||||
|
test_mqtt_broker:publish(CommandTopic, CommandJson, 0),
|
||||||
|
timer:sleep(50),
|
||||||
|
Request2 = test_recv_coap_request(UdpSock),
|
||||||
|
#coap_message{method = Method2, options=Options2, payload=Payload2} = Request2,
|
||||||
|
Path2 = get_coap_path(Options2),
|
||||||
|
?assertEqual(put, Method2),
|
||||||
|
?assertEqual(<<"/1/0/2">>, Path2),
|
||||||
|
?assertMatch([#{value := 129}], emqx_lwm2m_message:tlv_to_json(Path2, Payload2)),
|
||||||
|
|
||||||
|
timer:sleep(50),
|
||||||
|
|
||||||
|
test_send_coap_response(UdpSock, "127.0.0.1", ?PORT, {ok, changed}, #coap_content{}, Request2, true),
|
||||||
|
timer:sleep(100),
|
||||||
|
|
||||||
|
ReadResult = emqx_json:encode(#{
|
||||||
|
<<"requestID">> => CmdId, <<"cacheID">> => CmdId,
|
||||||
|
<<"data">> => #{
|
||||||
|
<<"reqPath">> => <<"/1/0/2">>,
|
||||||
|
<<"code">> => <<"2.04">>,
|
||||||
|
<<"codeMsg">> => <<"changed">>
|
||||||
|
},
|
||||||
|
<<"msgType">> => <<"write">>
|
||||||
|
}),
|
||||||
|
?assertEqual(ReadResult, test_recv_mqtt_response(RespTopic)).
|
||||||
|
|
||||||
case01_register(Config) ->
|
case01_register(Config) ->
|
||||||
% ----------------------------------------
|
% ----------------------------------------
|
||||||
% REGISTER command
|
% REGISTER command
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
-module(emqx_lwm2m_message_tests).
|
||||||
|
|
||||||
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
|
||||||
|
-import(emqx_lwm2m_message, [bits/1]).
|
||||||
|
|
||||||
|
bits_pos_test() ->
|
||||||
|
?assertEqual(8, bits(0)),
|
||||||
|
?assertEqual(8, bits(1)),
|
||||||
|
?assertEqual(8, bits(127)),
|
||||||
|
?assertEqual(16, bits(128)),
|
||||||
|
?assertEqual(16, bits(129)),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
bits_neg_test() ->
|
||||||
|
?assertEqual(8, bits(-1)),
|
||||||
|
?assertEqual(8, bits(-2)),
|
||||||
|
?assertEqual(8, bits(-127)),
|
||||||
|
?assertEqual(8, bits(-128)),
|
||||||
|
?assertEqual(16, bits(-129)),
|
||||||
|
ok.
|
Loading…
Reference in New Issue