fix: modbus_decoder

This commit is contained in:
AvantLiu 2022-02-18 14:41:53 +08:00
parent 95368fafd5
commit f8589991f5
3 changed files with 68 additions and 31 deletions

View File

@ -461,8 +461,7 @@ modbus_tcp_decoder(ProductId, TransactionId, Address, Data, Acc1) ->
NewAddress = Sh * 256 + Sl, NewAddress = Sh * 256 + Sl,
case {TransactionId, Address} of case {TransactionId, Address} of
{NewSlaveid, NewAddress} -> {NewSlaveid, NewAddress} ->
%% case format_value(Data, X, Props) of case format_value(Data, X, Props) of
case format_value(Data, X) of
{Value, _Rest} -> {Value, _Rest} ->
Acc#{Identifier => Value}; Acc#{Identifier => Value};
{map, Value, _Rest} -> {map, Value, _Rest} ->
@ -486,20 +485,24 @@ modbus_decoder(ProductId, SlaveId, Address, Data, Acc1) ->
case X of case X of
#{<<"identifier">> := Identifier, #{<<"identifier">> := Identifier,
<<"dataForm">> := #{ <<"dataForm">> := #{
<<"strategy">> := Strategy,
<<"slaveid">> := OldSlaveid, <<"slaveid">> := OldSlaveid,
<<"address">> := OldAddress, <<"address">> := OldAddress,
<<"protocol">> := <<"modbus">> <<"protocol">> := <<"modbus">>
}} -> }} when Strategy =/= <<"计算值"/utf8>> ->
<<H:8, L:8>> = dgiot_utils:hex_to_binary(modbus_rtu:is16(OldSlaveid)), <<H:8, L:8>> = dgiot_utils:hex_to_binary(modbus_rtu:is16(OldSlaveid)),
<<Sh:8, Sl:8>> = dgiot_utils:hex_to_binary(modbus_rtu:is16(OldAddress)), <<Sh:8, Sl:8>> = dgiot_utils:hex_to_binary(modbus_rtu:is16(OldAddress)),
NewSlaveid = H * 256 + L, NewSlaveid = H * 256 + L,
NewAddress = Sh * 256 + Sl, NewAddress = Sh * 256 + Sl,
case {SlaveId, Address} of case {SlaveId, Address} of
{NewSlaveid, NewAddress} -> {NewSlaveid, NewAddress} ->
case format_value(Data, X) of case format_value(Data, X, Props) of
{map, Value} ->
maps:merge(Acc, Value);
{Value, _Rest} -> {Value, _Rest} ->
Acc#{Identifier => Value}; Acc#{Identifier => Value};
_ -> Acc _A ->
Acc
end; end;
_ -> _ ->
Acc Acc
@ -540,30 +543,64 @@ modbus_encoder(ProductId, SlaveId, Address, Value) ->
%% 0x78 | 0x56 | 0x34 | 0x12 %% 0x78 | 0x56 | 0x34 | 0x12
format_value(Buff, #{ format_value(Buff, #{
<<"dataType">> := #{<<"type">> := <<"geopoint">>, <<"gpstype">> := <<"NMEA0183">>}}) -> <<"dataType">> := #{<<"type">> := <<"geopoint">>, <<"gpstype">> := <<"NMEA0183">>}}, _Props) ->
{Longitude, Latitude} = dgiot_gps:nmea0183_frame(Buff), {Longitude, Latitude} = dgiot_gps:nmea0183_frame(Buff),
{<<Longitude/binary, "_", Latitude/binary>>, <<"Rest">>}; {<<Longitude/binary, "_", Latitude/binary>>, <<"Rest">>};
format_value(Buff, #{ format_value(Buff, #{
<<"accessMode">> := <<"rw">>, <<"accessMode">> := <<"rw">>,
<<"dataForm">> := DataForm} = X) -> <<"dataForm">> := DataForm} = X, _Props) ->
format_value(Buff, X#{<<"accessMode">> => <<"r">>, format_value(Buff, X#{<<"accessMode">> => <<"r">>,
<<"dataForm">> => DataForm#{<<"data">> => byte_size(Buff)} <<"dataForm">> => DataForm#{<<"data">> => byte_size(Buff)}
}); }, _Props);
format_value(Buff, #{<<"dataForm">> := #{ format_value(Buff, #{<<"identifier">> := BitIdentifier,
<<"data">> := Len, <<"dataForm">> := #{
<<"originaltype">> := <<"bit">> <<"originaltype">> := <<"bit">>
}}) -> }}, Props) ->
IntLen = dgiot_utils:to_int(Len), Values =
Size = max(2, IntLen) * 8, lists:foldl(fun(X, Acc) ->
<<Value:Size, Rest/binary>> = Buff, case X of
{Value, Rest}; #{<<"identifier">> := Identifier,
<<"dataForm">> := #{
<<"slaveid">> := BitIdentifier,
<<"address">> := Offset,
<<"data">> := Len,
<<"protocol">> := <<"modbus">>,
<<"strategy">> := <<"计算值"/utf8>>
}} ->
IntOffset = dgiot_utils:to_int(Offset),
IntLen = dgiot_utils:to_int(Len),
Value =
case IntOffset of
0 ->
<<V:IntLen/binary, _/binary>> = Buff,
case format_value(V, X, Props) of
{Value1, _Rest} ->
Value1;
_ ->
V
end;
_ ->
<<_:IntOffset/binary, V:IntLen/binary, _/binary>> = Buff,
case format_value(V, X, Props) of
{Value1, _Rest} ->
Value1;
_ ->
V
end
end,
Acc#{Identifier => Value};
_ ->
Acc
end
end, #{}, Props),
{map, Values};
format_value(Buff, #{<<"dataForm">> := #{ format_value(Buff, #{<<"dataForm">> := #{
<<"data">> := Len, <<"data">> := Len,
<<"originaltype">> := <<"short16_AB">> <<"originaltype">> := <<"short16_AB">>
}}) -> }}, _Props) ->
IntLen = dgiot_utils:to_int(Len), IntLen = dgiot_utils:to_int(Len),
Size = max(2, IntLen) * 8, Size = max(2, IntLen) * 8,
<<Value:Size/signed-big-integer, Rest/binary>> = Buff, <<Value:Size/signed-big-integer, Rest/binary>> = Buff,
@ -572,7 +609,7 @@ format_value(Buff, #{<<"dataForm">> := #{
format_value(Buff, #{<<"dataForm">> := #{ format_value(Buff, #{<<"dataForm">> := #{
<<"data">> := Len, <<"data">> := Len,
<<"originaltype">> := <<"short16_BA">> <<"originaltype">> := <<"short16_BA">>
}}) -> }}, _Props) ->
IntLen = dgiot_utils:to_int(Len), IntLen = dgiot_utils:to_int(Len),
Size = max(2, IntLen) * 8, Size = max(2, IntLen) * 8,
<<Value:Size/signed-little-integer, Rest/binary>> = Buff, <<Value:Size/signed-little-integer, Rest/binary>> = Buff,
@ -581,7 +618,7 @@ format_value(Buff, #{<<"dataForm">> := #{
format_value(Buff, #{<<"dataForm">> := #{ format_value(Buff, #{<<"dataForm">> := #{
<<"data">> := Len, <<"data">> := Len,
<<"originaltype">> := <<"ushort16_AB">> <<"originaltype">> := <<"ushort16_AB">>
}}) -> }}, _Props) ->
IntLen = dgiot_utils:to_int(Len), IntLen = dgiot_utils:to_int(Len),
Size = max(2, IntLen) * 8, Size = max(2, IntLen) * 8,
<<Value:Size/unsigned-big-integer, Rest/binary>> = Buff, <<Value:Size/unsigned-big-integer, Rest/binary>> = Buff,
@ -590,7 +627,7 @@ format_value(Buff, #{<<"dataForm">> := #{
format_value(Buff, #{<<"dataForm">> := #{ format_value(Buff, #{<<"dataForm">> := #{
<<"data">> := Len, <<"data">> := Len,
<<"originaltype">> := <<"ushort16_BA">> <<"originaltype">> := <<"ushort16_BA">>
}}) -> }}, _Props) ->
IntLen = dgiot_utils:to_int(Len), IntLen = dgiot_utils:to_int(Len),
Size = max(2, IntLen) * 8, Size = max(2, IntLen) * 8,
<<Value:Size/unsigned-little-integer, Rest/binary>> = Buff, <<Value:Size/unsigned-little-integer, Rest/binary>> = Buff,
@ -599,7 +636,7 @@ format_value(Buff, #{<<"dataForm">> := #{
format_value(Buff, #{<<"dataForm">> := #{ format_value(Buff, #{<<"dataForm">> := #{
<<"data">> := Len, <<"data">> := Len,
<<"originaltype">> := <<"long32_ABCD">> <<"originaltype">> := <<"long32_ABCD">>
}}) -> }}, _Props) ->
IntLen = dgiot_utils:to_int(Len), IntLen = dgiot_utils:to_int(Len),
Size = max(4, IntLen) * 8, Size = max(4, IntLen) * 8,
<<H:2/binary, L:2/binary, Rest/binary>> = Buff, <<H:2/binary, L:2/binary, Rest/binary>> = Buff,
@ -609,7 +646,7 @@ format_value(Buff, #{<<"dataForm">> := #{
format_value(Buff, #{<<"dataForm">> := #{ format_value(Buff, #{<<"dataForm">> := #{
<<"data">> := Len, <<"data">> := Len,
<<"originaltype">> := <<"long32_CDAB">> <<"originaltype">> := <<"long32_CDAB">>
}}) -> }}, _Props) ->
IntLen = dgiot_utils:to_int(Len), IntLen = dgiot_utils:to_int(Len),
Size = max(4, IntLen) * 8, Size = max(4, IntLen) * 8,
<<H:2/binary, L:2/binary, Rest/binary>> = Buff, <<H:2/binary, L:2/binary, Rest/binary>> = Buff,
@ -619,7 +656,7 @@ format_value(Buff, #{<<"dataForm">> := #{
format_value(Buff, #{<<"dataForm">> := #{ format_value(Buff, #{<<"dataForm">> := #{
<<"data">> := Len, <<"data">> := Len,
<<"originaltype">> := <<"ulong32_ABCD">> <<"originaltype">> := <<"ulong32_ABCD">>
}}) -> }}, _Props) ->
IntLen = dgiot_utils:to_int(Len), IntLen = dgiot_utils:to_int(Len),
Size = max(4, IntLen) * 8, Size = max(4, IntLen) * 8,
<<H:2/binary, L:2/binary, Rest/binary>> = Buff, <<H:2/binary, L:2/binary, Rest/binary>> = Buff,
@ -629,7 +666,7 @@ format_value(Buff, #{<<"dataForm">> := #{
format_value(Buff, #{<<"dataForm">> := #{ format_value(Buff, #{<<"dataForm">> := #{
<<"data">> := Len, <<"data">> := Len,
<<"originaltype">> := <<"ulong32_CDAB">> <<"originaltype">> := <<"ulong32_CDAB">>
}}) -> }}, _Props) ->
IntLen = dgiot_utils:to_int(Len), IntLen = dgiot_utils:to_int(Len),
Size = max(4, IntLen) * 8, Size = max(4, IntLen) * 8,
<<H:2/binary, L:2/binary, Rest/binary>> = Buff, <<H:2/binary, L:2/binary, Rest/binary>> = Buff,
@ -639,7 +676,7 @@ format_value(Buff, #{<<"dataForm">> := #{
format_value(Buff, #{<<"dataForm">> := #{ format_value(Buff, #{<<"dataForm">> := #{
<<"data">> := Len, <<"data">> := Len,
<<"originaltype">> := <<"float32_ABCD">> <<"originaltype">> := <<"float32_ABCD">>
}}) -> }}, _Props) ->
IntLen = dgiot_utils:to_int(Len), IntLen = dgiot_utils:to_int(Len),
Size = max(4, IntLen) * 8, Size = max(4, IntLen) * 8,
<<H:2/binary, L:2/binary, Rest/binary>> = Buff, <<H:2/binary, L:2/binary, Rest/binary>> = Buff,
@ -649,7 +686,7 @@ format_value(Buff, #{<<"dataForm">> := #{
format_value(Buff, #{<<"dataForm">> := #{ format_value(Buff, #{<<"dataForm">> := #{
<<"data">> := Len, <<"data">> := Len,
<<"originaltype">> := <<"float32_CDAB">> <<"originaltype">> := <<"float32_CDAB">>
}}) -> }}, _Props) ->
IntLen = dgiot_utils:to_int(Len), IntLen = dgiot_utils:to_int(Len),
Size = max(4, IntLen) * 8, Size = max(4, IntLen) * 8,
<<H:2/binary, L:2/binary, Rest/binary>> = Buff, <<H:2/binary, L:2/binary, Rest/binary>> = Buff,
@ -657,6 +694,6 @@ format_value(Buff, #{<<"dataForm">> := #{
{Value, Rest}; {Value, Rest};
%% @todo %% @todo
format_value(_, #{<<"identifier">> := Field}) -> format_value(_, #{<<"identifier">> := Field}, _Props) ->
?LOG(info, "Field ~p", [Field]), ?LOG(info, "Field ~p", [Field]),
throw({field_error, <<Field/binary, " is not validate">>}). throw({field_error, <<Field/binary, " is not validate">>}).

View File

@ -114,7 +114,7 @@ handle_message({sync_parse, Args, ObjectId}, State) ->
#{<<"profile">> := _Profile, <<"devaddr">> := _Devaddr, <<"product">> := #{<<"objectId">> := _ProductId}} -> #{<<"profile">> := _Profile, <<"devaddr">> := _Devaddr, <<"product">> := #{<<"objectId">> := _ProductId}} ->
handle_message({sync_parse, Args}, State); handle_message({sync_parse, Args}, State);
#{<<"profile">> := Profile} -> #{<<"profile">> := Profile} ->
io:format("~s ~p ObjectId = ~p.~n", [?FILE, ?LINE, ObjectId]), %% io:format("~s ~p ObjectId = ~p.~n", [?FILE, ?LINE, ObjectId]),
case dgiot_device:lookup(dgiot_utils:to_binary(ObjectId)) of case dgiot_device:lookup(dgiot_utils:to_binary(ObjectId)) of
{ok, #{<<"devaddr">> := Devaddr, <<"productid">> := ProductId}} -> {ok, #{<<"devaddr">> := Devaddr, <<"productid">> := ProductId}} ->
NewArgs = jsx:encode(#{<<"profile">> => Profile, <<"devaddr">> => Devaddr, <<"product">> => #{<<"objectId">> => ProductId}}), NewArgs = jsx:encode(#{<<"profile">> => Profile, <<"devaddr">> => Devaddr, <<"product">> => #{<<"objectId">> => ProductId}}),
@ -133,7 +133,7 @@ handle_message({sync_parse, Args, ObjectId}, State) ->
end; end;
handle_message({sync_parse, Args}, State) -> handle_message({sync_parse, Args}, State) ->
io:format("~s ~p Args = ~p.~n", [?FILE, ?LINE, jsx:decode(Args, [{labels, binary}, return_maps])]), %% io:format("~s ~p Args = ~p.~n", [?FILE, ?LINE, jsx:decode(Args, [{labels, binary}, return_maps])]),
case jsx:decode(Args, [{labels, binary}, return_maps]) of case jsx:decode(Args, [{labels, binary}, return_maps]) of
#{<<"profile">> := Profile, <<"devaddr">> := Devaddr, <<"product">> := #{<<"objectId">> := ProductId}} = Arg -> #{<<"profile">> := Profile, <<"devaddr">> := Devaddr, <<"product">> := #{<<"objectId">> := ProductId}} = Arg ->
Sessiontoken = maps:get(<<"sessiontoken">>, Arg, <<"">>), Sessiontoken = maps:get(<<"sessiontoken">>, Arg, <<"">>),

View File

@ -146,7 +146,7 @@ handle_info(retry, State) ->
handle_info({deliver, _, Msg}, #task{tid = Channel, dis = Dis, product = ProductId, devaddr = DevAddr, ack = Ack, que = Que} = State) when length(Que) == 0 -> handle_info({deliver, _, Msg}, #task{tid = Channel, dis = Dis, product = ProductId, devaddr = DevAddr, ack = Ack, que = Que} = State) when length(Que) == 0 ->
Payload = jsx:decode(dgiot_mqtt:get_payload(Msg), [return_maps]), Payload = jsx:decode(dgiot_mqtt:get_payload(Msg), [return_maps]),
dgiot_bridge:send_log(Channel, ProductId, DevAddr, "~s ~p ~ts: ~ts ", [?FILE, ?LINE, unicode:characters_to_list(dgiot_mqtt:get_topic(Msg)), unicode:characters_to_list(dgiot_mqtt:get_payload(Msg))]), dgiot_bridge:send_log(Channel, ProductId, DevAddr, "~s ~p ~ts: ~ts ", [?FILE, ?LINE, unicode:characters_to_list(dgiot_mqtt:get_topic(Msg)), unicode:characters_to_list(dgiot_mqtt:get_payload(Msg))]),
NewAck = dgiot_task:get_collection(ProductId, Dis, Payload, Ack), NewAck = dgiot_task:get_collection(ProductId, Dis, Payload, maps:merge(Ack, Payload)),
dgiot_metrics:inc(dgiot_task, <<"task_recv">>, 1), dgiot_metrics:inc(dgiot_task, <<"task_recv">>, 1),
{noreply, get_next_pn(State#task{ack = NewAck})}; {noreply, get_next_pn(State#task{ack = NewAck})};
@ -246,8 +246,8 @@ save_td(#task{app = _App, tid = Channel, product = ProductId, devaddr = DevAddr,
0 -> 0 ->
pass; pass;
_ -> _ ->
dgiot_bridge:send_log(Channel, ProductId, DevAddr, "save_td=> ~s ~p ~p: ~ts ", [?FILE, ?LINE, ProductId, unicode:characters_to_list(jsx:encode(Ack))]),
Data = dgiot_task:get_calculated(ProductId, Ack), Data = dgiot_task:get_calculated(ProductId, Ack),
dgiot_bridge:send_log(Channel, ProductId, DevAddr, "save_td=> ~s ~p ~p: ~ts ", [?FILE, ?LINE, ProductId, unicode:characters_to_list(jsx:encode(Data))]),
case length(maps:to_list(Data)) of case length(maps:to_list(Data)) of
0 -> 0 ->
pass; pass;