1 |
|
%%------------------------------------------------------------------------- |
2 |
|
%% Copyright (c) 2020-2022 EMQ Technologies Co., Ltd. All Rights Reserved. |
3 |
|
%% |
4 |
|
%% Licensed under the Apache License, Version 2.0 (the "License"); |
5 |
|
%% you may not use this file except in compliance with the License. |
6 |
|
%% You may obtain a copy of the License at |
7 |
|
%% |
8 |
|
%% http://www.apache.org/licenses/LICENSE-2.0 |
9 |
|
%% |
10 |
|
%% Unless required by applicable law or agreed to in writing, software |
11 |
|
%% distributed under the License is distributed on an "AS IS" BASIS, |
12 |
|
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 |
|
%% See the License for the specific language governing permissions and |
14 |
|
%% limitations under the License. |
15 |
|
%%------------------------------------------------------------------------- |
16 |
|
|
17 |
|
%% @doc MQTT-SN frame parser and serializer |
18 |
|
%% |
19 |
|
%% @private |
20 |
|
-module(emqttsn_frame). |
21 |
|
|
22 |
|
-include_lib("stdlib/include/assert.hrl"). |
23 |
|
|
24 |
|
-include("emqttsn.hrl"). |
25 |
|
|
26 |
|
-export([parse/1, parse/2, serialize/1, serialize/2, parse_leading_len/2]). |
27 |
|
|
28 |
|
-type parse_result() :: {ok, #mqttsn_packet{}} | {error, term()}. |
29 |
|
|
30 |
|
-spec boolean_to_integer(boolean()) -> 0 | 1. |
31 |
|
boolean_to_integer(Bool) -> |
32 |
348 |
case Bool of |
33 |
|
true -> |
34 |
60 |
1; |
35 |
|
false -> |
36 |
288 |
0 |
37 |
|
end. |
38 |
|
|
39 |
|
-spec integer_to_boolean(0 | 1) -> boolean(). |
40 |
|
integer_to_boolean(Value) -> |
41 |
56 |
case Value of |
42 |
|
1 -> |
43 |
:-( |
true; |
44 |
|
0 -> |
45 |
56 |
false |
46 |
|
end. |
47 |
|
|
48 |
|
%%-------------------------------------------------------------------- |
49 |
|
%% Init Config State |
50 |
|
%%-------------------------------------------------------------------- |
51 |
|
|
52 |
|
%%-------------------------------------------------------------------- |
53 |
|
%% Parse MQTT-SN Frame |
54 |
|
%%-------------------------------------------------------------------- |
55 |
|
|
56 |
|
% parser API for packet |
57 |
|
-spec parse(bitstring()) -> parse_result(). |
58 |
|
parse(Bin) -> |
59 |
64 |
parse(Bin, #config{}). |
60 |
|
|
61 |
|
-spec parse(bitstring(), config()) -> parse_result(). |
62 |
|
parse(Bin, Config) -> |
63 |
64 |
case parse_leading_len(Bin, Config) of |
64 |
|
{ok, Length, LeadingLength, Rest} -> |
65 |
64 |
#config{strict_mode = StrictMode} = Config, |
66 |
64 |
StrictMode andalso ?assertEqual(byte_size(Rest) + LeadingLength, Length), |
67 |
64 |
{ok, parse_payload_from_type(Rest, Config)}; |
68 |
|
{error, Reason} -> |
69 |
:-( |
{error, Reason} |
70 |
|
end. |
71 |
|
|
72 |
|
-spec parse_leading_len(bitstring(), #config{}) -> |
73 |
|
{ok, pos_integer(), pos_integer(), bitstring()} | {error, term()}. |
74 |
|
parse_leading_len(<<16#01:8/integer, Length:16/integer, Rest/binary>>, Config) -> |
75 |
3 |
SelfLength = 3, |
76 |
3 |
#config{max_size = MaxSize} = Config, |
77 |
3 |
case Length =< MaxSize of |
78 |
|
true -> |
79 |
2 |
{ok, Length, SelfLength, Rest}; |
80 |
|
false -> |
81 |
1 |
{error, frame_too_large} |
82 |
|
end; |
83 |
|
parse_leading_len(<<Length:8/integer, Rest/binary>>, Config) -> |
84 |
67 |
SelfLength = 1, |
85 |
67 |
#config{max_size = MaxSize} = Config, |
86 |
67 |
case Length =< MaxSize of |
87 |
|
true -> |
88 |
66 |
{ok, Length, SelfLength, Rest}; |
89 |
|
false -> |
90 |
1 |
{error, frame_too_large} |
91 |
|
end. |
92 |
|
|
93 |
|
% parse the message type to a header of packet |
94 |
|
-spec parse_payload_from_type(binary(), #config{}) -> mqttsn_packet(). |
95 |
|
parse_payload_from_type(<<Type:8/integer, Rest/binary>>, Config) -> |
96 |
64 |
Header = #mqttsn_packet_header{type = Type}, |
97 |
64 |
Payload = parse_payload(Rest, Header, Config), |
98 |
64 |
#mqttsn_packet{header = Header, payload = Payload}. |
99 |
|
|
100 |
|
% dispatch to the parser of different message type |
101 |
|
-spec parse_payload(binary(), #mqttsn_packet_header{}, #config{}) -> packet_payload(). |
102 |
|
parse_payload(<<GwId:8/integer, Duration:16/integer>>, |
103 |
|
#mqttsn_packet_header{type = ?ADVERTISE}, |
104 |
|
_Config) -> |
105 |
1 |
#mqttsn_packet_advertise{gateway_id = GwId, duration = Duration}; |
106 |
|
parse_payload(<<Radius:8/integer>>, #mqttsn_packet_header{type = ?SEARCHGW}, _Config) -> |
107 |
:-( |
#mqttsn_packet_searchgw{radius = Radius}; |
108 |
|
parse_payload(Bin, #mqttsn_packet_header{type = ?GWINFO}, Config) -> |
109 |
3 |
parse_gwinfo_msg(Bin, Config); |
110 |
|
parse_payload(<<ReturnCode:8/integer>>, |
111 |
|
#mqttsn_packet_header{type = ?CONNACK}, |
112 |
|
_Config) -> |
113 |
18 |
#mqttsn_packet_connack{return_code = ReturnCode}; |
114 |
|
parse_payload(<<>>, #mqttsn_packet_header{type = ?WILLTOPICREQ}, _Config) -> |
115 |
1 |
#mqttsn_packet_willtopicreq{}; |
116 |
|
parse_payload(<<>>, #mqttsn_packet_header{type = ?WILLMSGREQ}, _Config) -> |
117 |
1 |
#mqttsn_packet_willmsgreq{}; |
118 |
|
parse_payload(<<TopicId:16/integer, MsgId:16/integer, TopicNameBin/binary>>, |
119 |
|
#mqttsn_packet_header{type = ?REGISTER}, |
120 |
|
_Config) -> |
121 |
:-( |
TopicName = binary_to_list(TopicNameBin), |
122 |
:-( |
#mqttsn_packet_register{source = ?SERVER, |
123 |
|
topic_id = TopicId, |
124 |
|
packet_id = MsgId, |
125 |
|
topic_name = TopicName}; |
126 |
|
parse_payload(<<TopicId:16/integer, MsgId:16/integer, ReturnCode:8/integer>>, |
127 |
|
#mqttsn_packet_header{type = ?REGACK}, |
128 |
|
_Config) -> |
129 |
6 |
#mqttsn_packet_regack{topic_id = TopicId, |
130 |
|
packet_id = MsgId, |
131 |
|
return_code = ReturnCode}; |
132 |
|
parse_payload(<<SerFlag:1/binary, |
133 |
|
TopicIdOrNameBin:2/binary, |
134 |
|
MsgId:16/integer, |
135 |
|
MessageBin/bitstring>>, |
136 |
|
#mqttsn_packet_header{type = ?PUBLISH}, |
137 |
|
Config) -> |
138 |
6 |
Message = binary_to_list(MessageBin), |
139 |
6 |
Flag = parse_flag(SerFlag, Config), |
140 |
6 |
#mqttsn_packet_flag{topic_id_type = TopicIdType} = Flag, |
141 |
6 |
case TopicIdType of |
142 |
|
?SHORT_TOPIC_NAME -> |
143 |
4 |
#mqttsn_packet_publish{flag = Flag, |
144 |
|
topic_id_or_name = binary_to_list(TopicIdOrNameBin), |
145 |
|
packet_id = MsgId, |
146 |
|
message = Message}; |
147 |
|
_ -> |
148 |
2 |
<<TopicIdOrName:16/integer>> = TopicIdOrNameBin, |
149 |
2 |
#mqttsn_packet_publish{flag = Flag, |
150 |
|
topic_id_or_name = TopicIdOrName, |
151 |
|
packet_id = MsgId, |
152 |
|
message = Message} |
153 |
|
end; |
154 |
|
parse_payload(<<TopicId:16/integer, MsgId:16/integer, ReturnCode:8/integer>>, |
155 |
|
#mqttsn_packet_header{type = ?PUBACK}, |
156 |
|
_Config) -> |
157 |
2 |
#mqttsn_packet_puback{topic_id = TopicId, |
158 |
|
packet_id = MsgId, |
159 |
|
return_code = ReturnCode}; |
160 |
|
parse_payload(<<MsgId:16/integer>>, #mqttsn_packet_header{type = ?PUBREC}, _Config) -> |
161 |
1 |
#mqttsn_packet_pubrec{packet_id = MsgId}; |
162 |
|
parse_payload(<<MsgId:16/integer>>, #mqttsn_packet_header{type = ?PUBREL}, _Config) -> |
163 |
:-( |
#mqttsn_packet_pubrel{packet_id = MsgId}; |
164 |
|
parse_payload(<<MsgId:16/integer>>, #mqttsn_packet_header{type = ?PUBCOMP}, _Config) -> |
165 |
1 |
#mqttsn_packet_pubcomp{packet_id = MsgId}; |
166 |
|
parse_payload(<<Flag:1/binary, |
167 |
|
TopicId:16/integer, |
168 |
|
MsgId:16/integer, |
169 |
|
ReturnCode:8/integer>>, |
170 |
|
#mqttsn_packet_header{type = ?SUBACK}, |
171 |
|
Config) -> |
172 |
8 |
#mqttsn_packet_suback{flag = parse_flag(Flag, Config), |
173 |
|
topic_id = TopicId, |
174 |
|
packet_id = MsgId, |
175 |
|
return_code = ReturnCode}; |
176 |
|
parse_payload(<<MsgId:16/integer>>, #mqttsn_packet_header{type = ?UNSUBACK}, _Config) -> |
177 |
1 |
#mqttsn_packet_unsuback{packet_id = MsgId}; |
178 |
|
parse_payload(<<ClienIdBin/binary>>, #mqttsn_packet_header{type = ?PINGREQ}, _Config) -> |
179 |
1 |
ClienId = binary_to_list(ClienIdBin), |
180 |
1 |
#mqttsn_packet_pingreq{empty_packet = false, client_id = ClienId}; |
181 |
|
parse_payload(<<>>, #mqttsn_packet_header{type = ?PINGRESP}, _Config) -> |
182 |
2 |
#mqttsn_packet_pingresp{}; |
183 |
|
parse_payload(Bin, #mqttsn_packet_header{type = ?DISCONNECT}, Config) -> |
184 |
12 |
parse_disconnect_msg(Bin, Config); |
185 |
|
parse_payload(<<ReturnCode:8/integer>>, |
186 |
|
#mqttsn_packet_header{type = ?WILLTOPICRESP}, |
187 |
|
_Config) -> |
188 |
:-( |
#mqttsn_packet_willtopicresp{return_code = ReturnCode}; |
189 |
|
parse_payload(<<ReturnCode:8/integer>>, |
190 |
|
#mqttsn_packet_header{type = ?WILLMSGRESP}, |
191 |
|
_Config) -> |
192 |
:-( |
#mqttsn_packet_willmsgresp{return_code = ReturnCode}. |
193 |
|
|
194 |
|
-spec parse_flag(binary(), #config{}) -> flag(). |
195 |
|
parse_flag(<<DUP:1/integer, |
196 |
|
Qos:2/integer, |
197 |
|
Retain:1/integer, |
198 |
|
Will:1/integer, |
199 |
|
CleanSession:1/integer, |
200 |
|
TopicIdType:2/integer>>, |
201 |
|
_Config) -> |
202 |
14 |
#mqttsn_packet_flag{dup = integer_to_boolean(DUP), |
203 |
|
qos = Qos, |
204 |
|
retain = integer_to_boolean(Retain), |
205 |
|
will = integer_to_boolean(Will), |
206 |
|
clean_session = integer_to_boolean(CleanSession), |
207 |
|
topic_id_type = TopicIdType}. |
208 |
|
|
209 |
|
-spec parse_gwinfo_msg(binary(), #config{}) -> packet_payload(). |
210 |
|
parse_gwinfo_msg(<<GWId:8/integer>>, _Config) -> |
211 |
2 |
#mqttsn_packet_gwinfo{source = ?SERVER, gateway_id = GWId}; |
212 |
|
parse_gwinfo_msg(<<GWId:8/integer, |
213 |
|
Adr1:8/integer, |
214 |
|
Adr2:8/integer, |
215 |
|
Adr3:8/integer, |
216 |
|
Adr4:8/integer>>, |
217 |
|
_Config) -> |
218 |
1 |
#mqttsn_packet_gwinfo{source = ?CLIENT, |
219 |
|
gateway_id = GWId, |
220 |
|
gateway_add = {Adr1, Adr2, Adr3, Adr4}}. |
221 |
|
|
222 |
|
-spec parse_disconnect_msg(binary(), #config{}) -> packet_payload(). |
223 |
|
parse_disconnect_msg(<<>>, _Config) -> |
224 |
12 |
#mqttsn_packet_disconnect{empty_packet = true}; |
225 |
|
parse_disconnect_msg(<<Duration:16/integer>>, _Config) -> |
226 |
:-( |
#mqttsn_packet_disconnect{empty_packet = false, duration = Duration}. |
227 |
|
|
228 |
|
%%-------------------------------------------------------------------- |
229 |
|
%% Serialize MQTT Packet |
230 |
|
%%-------------------------------------------------------------------- |
231 |
|
|
232 |
|
-spec serialize(#mqttsn_packet{}) -> bitstring(). |
233 |
|
serialize(Packet) -> |
234 |
:-( |
serialize(Packet, #config{}). |
235 |
|
|
236 |
|
-spec serialize(#mqttsn_packet{}, #config{}) -> bitstring(). |
237 |
|
serialize(#mqttsn_packet{header = Header, payload = Payload}, Config) -> |
238 |
192 |
PayloadBin = serialize_payload(Payload, Config), |
239 |
192 |
Length = iolist_size(PayloadBin), |
240 |
192 |
WholeLength = |
241 |
|
case Length of |
242 |
|
L when L =< 256 -> |
243 |
190 |
Length + 2; |
244 |
|
L when 256 < L andalso L < ?MAX_PACKET_SIZE -> |
245 |
2 |
Length + 4 |
246 |
|
end, |
247 |
192 |
HeaderBin = serialize_header(Header, WholeLength, Config), |
248 |
|
|
249 |
192 |
<<HeaderBin/binary, PayloadBin/binary>>. |
250 |
|
|
251 |
|
-spec serialize_header(#mqttsn_packet_header{}, non_neg_integer(), #config{}) -> binary(). |
252 |
|
serialize_header(#mqttsn_packet_header{type = Type}, Length, _Config) when Length < 256 -> |
253 |
190 |
<<Length:8/integer, Type:8/integer>>; |
254 |
|
serialize_header(#mqttsn_packet_header{type = Type}, Length, _Config) |
255 |
|
when 256 =< Length andalso Length =< ?MAX_PACKET_SIZE -> |
256 |
2 |
<<1:8/integer, Length:16/integer, Type:8/integer>>. |
257 |
|
|
258 |
|
-spec serialize_flag(#mqttsn_packet_flag{}, #config{}) -> bin_1_byte(). |
259 |
|
serialize_flag(#mqttsn_packet_flag{dup = Dup, |
260 |
|
qos = Qos, |
261 |
|
retain = Retain, |
262 |
|
will = Will, |
263 |
|
clean_session = CleanSession, |
264 |
|
topic_id_type = TopicIdType}, |
265 |
|
_Config) -> |
266 |
87 |
DupValue = boolean_to_integer(Dup), |
267 |
87 |
RetainValue = boolean_to_integer(Retain), |
268 |
87 |
WillValue = boolean_to_integer(Will), |
269 |
87 |
CleanSessionValue = boolean_to_integer(CleanSession), |
270 |
87 |
<<DupValue:1/integer, |
271 |
|
Qos:2/integer, |
272 |
|
RetainValue:1/integer, |
273 |
|
WillValue:1/integer, |
274 |
|
CleanSessionValue:1/integer, |
275 |
|
TopicIdType:2/integer>>. |
276 |
|
|
277 |
|
-spec serialize_payload(packet_payload(), #config{}) -> iodata(). |
278 |
|
serialize_payload(#mqttsn_packet_advertise{gateway_id = GwId, duration = Duration}, |
279 |
|
_Config) -> |
280 |
1 |
<<GwId:8/integer, Duration:16/integer>>; |
281 |
|
serialize_payload(#mqttsn_packet_searchgw{radius = Radius}, _Config) -> |
282 |
54 |
<<Radius:8>>; |
283 |
|
serialize_payload(#mqttsn_packet_gwinfo{source = ?CLIENT, |
284 |
|
gateway_id = GWId, |
285 |
|
gateway_add = GateWayAdd}, |
286 |
|
_Config) -> |
287 |
1 |
{Adr1, Adr2, Adr3, Adr4} = GateWayAdd, |
288 |
1 |
<<GWId:8/integer, Adr1:8/integer, Adr2:8/integer, Adr3:8/integer, Adr4:8/integer>>; |
289 |
|
serialize_payload(#mqttsn_packet_gwinfo{source = ?SERVER, gateway_id = GWId}, _Config) -> |
290 |
1 |
<<GWId:8/integer>>; |
291 |
|
serialize_payload(#mqttsn_packet_connect{flag = Flag, |
292 |
|
duration = Duration, |
293 |
|
client_id = ClientId}, |
294 |
|
Config) -> |
295 |
48 |
SerFlag = serialize_flag(Flag, Config), |
296 |
48 |
ClientIdBin = list_to_binary(ClientId), |
297 |
48 |
<<SerFlag/bitstring, 1:8/integer, Duration:16/integer, ClientIdBin/binary>>; |
298 |
|
serialize_payload(#mqttsn_packet_connack{return_code = ReturnCode}, _Config) -> |
299 |
1 |
<<ReturnCode:8/integer>>; |
300 |
|
serialize_payload(#mqttsn_packet_willtopicreq{}, _Config) -> |
301 |
:-( |
<<>>; |
302 |
|
serialize_payload(#mqttsn_packet_willtopic{} = Bin, Config) -> |
303 |
1 |
serialize_will_topic(Bin, Config); |
304 |
|
serialize_payload(#mqttsn_packet_willmsgreq{}, _Config) -> |
305 |
:-( |
<<>>; |
306 |
|
serialize_payload(#mqttsn_packet_willmsg{will_msg = WillMsg}, _Config) -> |
307 |
1 |
WillMsgBin = list_to_binary(WillMsg), |
308 |
1 |
WillMsgBin; |
309 |
|
serialize_payload(#mqttsn_packet_register{source = ?SERVER, |
310 |
|
topic_id = TopicId, |
311 |
|
packet_id = MsgId, |
312 |
|
topic_name = TopicName}, |
313 |
|
_Config) -> |
314 |
:-( |
TopicNameBin = list_to_binary(TopicName), |
315 |
:-( |
<<TopicId:16/integer, MsgId:16/integer, TopicNameBin/binary>>; |
316 |
|
serialize_payload(#mqttsn_packet_register{source = ?CLIENT, |
317 |
|
topic_id = _TopicId, |
318 |
|
packet_id = MsgId, |
319 |
|
topic_name = TopicName}, |
320 |
|
_Config) -> |
321 |
12 |
TopicNameBin = list_to_binary(TopicName), |
322 |
12 |
<<0:16/integer, MsgId:16/integer, TopicNameBin/binary>>; |
323 |
|
serialize_payload(#mqttsn_packet_regack{topic_id = TopicId, |
324 |
|
packet_id = MsgId, |
325 |
|
return_code = _ReturnCode}, |
326 |
|
_Config) -> |
327 |
1 |
<<TopicId:16/integer, MsgId:16/integer, 8/integer>>; |
328 |
|
serialize_payload(#mqttsn_packet_publish{flag = Flag, |
329 |
|
topic_id_or_name = TopicIdOrName, |
330 |
|
packet_id = MsgId, |
331 |
|
message = Message}, |
332 |
|
Config) -> |
333 |
16 |
MessageBin = list_to_binary(Message), |
334 |
16 |
SerFlag = serialize_flag(Flag, Config), |
335 |
16 |
#mqttsn_packet_flag{topic_id_type = TopicIdType} = Flag, |
336 |
16 |
case TopicIdType of |
337 |
|
?SHORT_TOPIC_NAME -> |
338 |
12 |
TopicNameBin = list_to_binary(TopicIdOrName), |
339 |
12 |
<<SerFlag:1/binary, TopicNameBin:2/binary, MsgId:16/integer, MessageBin/binary>>; |
340 |
|
_ -> |
341 |
4 |
TopicId = TopicIdOrName, |
342 |
4 |
<<SerFlag:1/binary, TopicId:16/integer, MsgId:16/integer, MessageBin/binary>> |
343 |
|
end; |
344 |
|
serialize_payload(#mqttsn_packet_puback{topic_id = TopicId, |
345 |
|
packet_id = MsgId, |
346 |
|
return_code = ReturnCode}, |
347 |
|
_Config) -> |
348 |
1 |
<<TopicId:16/integer, MsgId:16/integer, ReturnCode:8/integer>>; |
349 |
|
serialize_payload(#mqttsn_packet_pubrec{packet_id = MsgId}, _Config) -> |
350 |
:-( |
<<MsgId:16/integer>>; |
351 |
|
serialize_payload(#mqttsn_packet_pubrel{packet_id = MsgId}, _Config) -> |
352 |
1 |
<<MsgId:16/integer>>; |
353 |
|
serialize_payload(#mqttsn_packet_pubcomp{packet_id = MsgId}, _Config) -> |
354 |
:-( |
<<MsgId:16/integer>>; |
355 |
|
serialize_payload(#mqttsn_packet_suback{flag = Flag, |
356 |
|
topic_id = TopicId, |
357 |
|
packet_id = MsgId, |
358 |
|
return_code = ReturnCode}, |
359 |
|
Config) -> |
360 |
1 |
SerFlag = serialize_flag(Flag, Config), |
361 |
1 |
<<SerFlag:1/binary, TopicId:16/integer, MsgId:16/integer, ReturnCode:8/integer>>; |
362 |
|
serialize_payload(#mqttsn_packet_subscribe{flag = Flag, |
363 |
|
packet_id = MsgId, |
364 |
|
topic_name = TopicName, |
365 |
|
topic_id = TopicId}, |
366 |
|
Config) -> |
367 |
14 |
SerFlag = serialize_flag(Flag, Config), |
368 |
14 |
Bin = serialize_topic_name_or_id(Flag, TopicName, TopicId, Config), |
369 |
14 |
<<SerFlag:1/binary, MsgId:16/integer, Bin/binary>>; |
370 |
|
serialize_payload(#mqttsn_packet_unsubscribe{flag = Flag, |
371 |
|
packet_id = MsgId, |
372 |
|
topic_name = TopicName, |
373 |
|
topic_id = TopicId}, |
374 |
|
Config) -> |
375 |
7 |
SerFlag = serialize_flag(Flag, Config), |
376 |
7 |
Bin = serialize_topic_name_or_id(Flag, TopicName, TopicId, Config), |
377 |
7 |
<<SerFlag:1/binary, MsgId:16/integer, Bin/binary>>; |
378 |
|
serialize_payload(#mqttsn_packet_unsuback{packet_id = MsgId}, _Config) -> |
379 |
:-( |
<<MsgId:16/integer>>; |
380 |
|
serialize_payload(#mqttsn_packet_pingreq{} = Bin, Config) -> |
381 |
3 |
serialize_pingreq(Bin, Config); |
382 |
|
serialize_payload(#mqttsn_packet_pingresp{}, _Config) -> |
383 |
2 |
<<>>; |
384 |
|
serialize_payload(#mqttsn_packet_disconnect{} = Bin, Config) -> |
385 |
26 |
serialize_disconnect(Bin, Config); |
386 |
|
serialize_payload(#mqttsn_packet_willtopicupd{} = Bin, Config) -> |
387 |
:-( |
serialize_willtopicupd(Bin, Config); |
388 |
|
serialize_payload(#mqttsn_packet_willtopicresp{return_code = ReturnCode}, _Config) -> |
389 |
:-( |
<<ReturnCode:8/integer>>; |
390 |
|
serialize_payload(#mqttsn_packet_willmsgupd{will_msg = WillMsg}, _Config) -> |
391 |
:-( |
list_to_binary(WillMsg); |
392 |
|
serialize_payload(#mqttsn_packet_willmsgresp{return_code = ReturnCode}, _Config) -> |
393 |
:-( |
<<ReturnCode:8/integer>>. |
394 |
|
|
395 |
|
% serialize willTopic packet payload |
396 |
|
-spec serialize_will_topic(#mqttsn_packet_willtopic{}, #config{}) -> iodata(). |
397 |
|
serialize_will_topic(#mqttsn_packet_willtopic{empty_packet = true}, _Config) -> |
398 |
:-( |
<<>>; |
399 |
|
serialize_will_topic(#mqttsn_packet_willtopic{empty_packet = false, |
400 |
|
flag = Flag, |
401 |
|
will_topic = WillTopic}, |
402 |
|
Config) -> |
403 |
1 |
WillTopicBin = list_to_binary(WillTopic), |
404 |
1 |
SerFlag = serialize_flag(Flag, Config), |
405 |
1 |
<<SerFlag/binary, WillTopicBin/binary>>. |
406 |
|
|
407 |
|
% serialize topicName or topicId by Flag argument topicIdType |
408 |
|
-spec serialize_topic_name_or_id(#mqttsn_packet_flag{}, |
409 |
|
string(), |
410 |
|
topic_id(), |
411 |
|
#config{}) -> |
412 |
|
bitstring(). |
413 |
|
serialize_topic_name_or_id(#mqttsn_packet_flag{topic_id_type = TopicIdType}, |
414 |
|
_TopicName, |
415 |
|
TopicId, |
416 |
|
_Config) |
417 |
|
when TopicIdType == ?PRE_DEF_TOPIC_ID orelse TopicIdType == ?TOPIC_ID -> |
418 |
2 |
<<TopicId:16/integer>>; |
419 |
|
serialize_topic_name_or_id(#mqttsn_packet_flag{topic_id_type = TopicIdType}, |
420 |
|
TopicName, |
421 |
|
_TopicId, |
422 |
|
_Config) |
423 |
|
when TopicIdType == ?SHORT_TOPIC_NAME -> |
424 |
19 |
list_to_binary(TopicName). |
425 |
|
|
426 |
|
% serialize pingReq packet payload |
427 |
|
-spec serialize_pingreq(#mqttsn_packet_pingreq{}, #config{}) -> iodata(). |
428 |
|
serialize_pingreq(#mqttsn_packet_pingreq{empty_packet = true}, _Config) -> |
429 |
2 |
<<>>; |
430 |
|
serialize_pingreq(#mqttsn_packet_pingreq{empty_packet = false, client_id = ClienId}, |
431 |
|
_Config) -> |
432 |
1 |
list_to_binary(ClienId). |
433 |
|
|
434 |
|
-spec serialize_disconnect(#mqttsn_packet_disconnect{}, #config{}) -> iodata(). |
435 |
|
serialize_disconnect(#mqttsn_packet_disconnect{empty_packet = true}, _Config) -> |
436 |
25 |
<<>>; |
437 |
|
serialize_disconnect(#mqttsn_packet_disconnect{empty_packet = false, duration = Duration}, |
438 |
|
_Config) -> |
439 |
1 |
<<Duration:16/integer>>. |
440 |
|
|
441 |
|
-spec serialize_willtopicupd(#mqttsn_packet_willtopicupd{}, #config{}) -> iodata(). |
442 |
|
serialize_willtopicupd(#mqttsn_packet_willtopicupd{empty_packet = true}, _Config) -> |
443 |
:-( |
<<>>; |
444 |
|
serialize_willtopicupd(#mqttsn_packet_willtopicupd{empty_packet = false, |
445 |
|
flag = Flag, |
446 |
|
will_topic = WillTopic}, |
447 |
|
Config) -> |
448 |
:-( |
SerFlag = serialize_flag(Flag, Config), |
449 |
:-( |
WillTopicBin = list_to_binary(WillTopic), |
450 |
:-( |
<<SerFlag/binary, WillTopicBin/binary>>. |