mqtt 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -368,7 +368,7 @@ module MQTT
368
368
  end
369
369
  body += encode_string(@topic)
370
370
  body += encode_short(@id) unless qos == 0
371
- body += payload.to_s.force_encoding('ASCII-8BIT')
371
+ body += payload.to_s.dup.force_encoding('ASCII-8BIT')
372
372
  return body
373
373
  end
374
374
 
@@ -780,9 +780,9 @@ module MQTT
780
780
 
781
781
  # Set one or more topic filters for the Subscribe packet
782
782
  # The topics parameter should be one of the following:
783
- # * String: subscribe to one topic with QOS 0
784
- # * Array: subscribe to multiple topics with QOS 0
785
- # * Hash: subscribe to multiple topics where the key is the topic and the value is the QOS level
783
+ # * String: subscribe to one topic with QoS 0
784
+ # * Array: subscribe to multiple topics with QoS 0
785
+ # * Hash: subscribe to multiple topics where the key is the topic and the value is the QoS level
786
786
  #
787
787
  # For example:
788
788
  # packet.topics = 'a/b'
@@ -877,7 +877,7 @@ module MQTT
877
877
  super(ATTR_DEFAULTS.merge(args))
878
878
  end
879
879
 
880
- # Set the granted QOS value for each of the topics that were subscribed to
880
+ # Set the granted QoS value for each of the topics that were subscribed to
881
881
  # Can either be an integer or an array or integers.
882
882
  def return_codes=(value)
883
883
  if value.is_a?(Array)
@@ -892,7 +892,7 @@ module MQTT
892
892
  # Get serialisation of packet's body
893
893
  def encode_body
894
894
  if @return_codes.empty?
895
- raise "no granted QOS given when serialising packet"
895
+ raise "no granted QoS given when serialising packet"
896
896
  end
897
897
  body = encode_short(@id)
898
898
  return_codes.each { |qos| body += encode_bytes(qos) }
@@ -24,6 +24,10 @@ class Encoding
24
24
  def to_s
25
25
  @name
26
26
  end
27
+
28
+ def name
29
+ @name
30
+ end
27
31
 
28
32
  UTF_8 = Encoding.new("UTF-8")
29
33
  ASCII_8BIT = Encoding.new("ASCII-8BIT")
@@ -0,0 +1,763 @@
1
+ # encoding: BINARY
2
+
3
+ module MQTT::SN
4
+
5
+ # Class representing a MQTT::SN Packet
6
+ # Performs binary encoding and decoding of headers
7
+ class Packet
8
+ attr_accessor :duplicate # Duplicate delivery flag
9
+ attr_accessor :qos # Quality of Service level
10
+ attr_accessor :retain # Retain flag
11
+ attr_accessor :request_will # Request that gateway prompts for Will
12
+ attr_accessor :clean_session # When true, subscriptions are deleted after disconnect
13
+ attr_accessor :topic_id_type # One of :normal, :predefined or :short
14
+
15
+ DEFAULTS = {}
16
+
17
+ # Parse buffer into new packet object
18
+ def self.parse(buffer)
19
+ # Parse the fixed header (length and type)
20
+ length,type_id,body = buffer.unpack('CCa*')
21
+ if length == 1
22
+ length,type_id,body = buffer.unpack('xnCa*')
23
+ end
24
+
25
+ # Double-check the length
26
+ if buffer.length != length
27
+ raise ProtocolException.new("Length of packet is not the same as the length header")
28
+ end
29
+
30
+ packet_class = PACKET_TYPES[type_id]
31
+ if packet_class.nil?
32
+ raise ProtocolException.new("Invalid packet type identifier: #{type_id}")
33
+ end
34
+
35
+ # Create a new packet object
36
+ packet = packet_class.new
37
+ packet.parse_body(body)
38
+
39
+ return packet
40
+ end
41
+
42
+ # Create a new empty packet
43
+ def initialize(args={})
44
+ update_attributes(self.class::DEFAULTS.merge(args))
45
+ end
46
+
47
+ def update_attributes(attr={})
48
+ attr.each_pair do |k,v|
49
+ send("#{k}=", v)
50
+ end
51
+ end
52
+
53
+ # Get the identifer for this packet type
54
+ def type_id
55
+ PACKET_TYPES.each_pair do |key, value|
56
+ return key if self.class == value
57
+ end
58
+ raise "Invalid packet type: #{self.class}"
59
+ end
60
+
61
+ # Serialise the packet
62
+ def to_s
63
+ # Get the packet's variable header and payload
64
+ body = self.encode_body
65
+
66
+ # Build up the body length field bytes
67
+ body_length = body.length
68
+ if body_length > 65531
69
+ raise "MQTT-SN Packet is too big, maximum packet body size is 65531"
70
+ elsif body_length > 253
71
+ [0x01, body_length + 4, type_id].pack('CnC') + body
72
+ else
73
+ [body_length + 2, type_id].pack('CC') + body
74
+ end
75
+ end
76
+
77
+ def parse_body(buffer)
78
+ end
79
+
80
+ protected
81
+
82
+ def parse_flags(flags)
83
+ self.duplicate = ((flags & 0x80) >> 7) == 0x01
84
+ self.qos = (flags & 0x60) >> 5
85
+ self.qos = -1 if self.qos == 3
86
+ self.retain = ((flags & 0x10) >> 4) == 0x01
87
+ self.request_will = ((flags & 0x08) >> 3) == 0x01
88
+ self.clean_session = ((flags & 0x04) >> 2) == 0x01
89
+ case (flags & 0x03)
90
+ when 0x0
91
+ self.topic_id_type = :normal
92
+ when 0x1
93
+ self.topic_id_type = :predefined
94
+ when 0x2
95
+ self.topic_id_type = :short
96
+ else
97
+ self.topic_id_type = nil
98
+ end
99
+ end
100
+
101
+ # Get serialisation of packet's body (variable header and payload)
102
+ def encode_body
103
+ '' # No body by default
104
+ end
105
+
106
+ def encode_flags
107
+ flags = 0x00
108
+ flags += 0x80 if duplicate
109
+ case qos
110
+ when -1
111
+ flags += 0x60
112
+ when 1
113
+ flags += 0x20
114
+ when 2
115
+ flags += 0x40
116
+ end
117
+ flags += 0x10 if retain
118
+ flags += 0x08 if request_will
119
+ flags += 0x04 if clean_session
120
+ case topic_id_type
121
+ when :normal
122
+ flags += 0x0
123
+ when :predefined
124
+ flags += 0x1
125
+ when :short
126
+ flags += 0x2
127
+ end
128
+ return flags
129
+ end
130
+
131
+ def encode_topic_id
132
+ if topic_id_type == :short
133
+ unless topic_id.is_a?(String)
134
+ raise "topic_id must be an String for type #{topic_id_type}"
135
+ end
136
+ (topic_id[0].ord << 8) + topic_id[1].ord
137
+ else
138
+ unless topic_id.is_a?(Integer)
139
+ raise "topic_id must be an Integer for type #{topic_id_type}"
140
+ end
141
+ topic_id
142
+ end
143
+ end
144
+
145
+ def parse_topic_id(topic_id)
146
+ if topic_id_type == :short
147
+ int = topic_id.to_i
148
+ self.topic_id = [(int >> 8) & 0xFF, int & 0xFF].pack('CC')
149
+ else
150
+ self.topic_id = topic_id
151
+ end
152
+ end
153
+
154
+ # Used where a field can either be a Topic Id or a Topic Name
155
+ # (the Subscribe and Unsubscribe packet types)
156
+ def encode_topic
157
+ case topic_id_type
158
+ when :normal
159
+ topic_name
160
+ when :short
161
+ unless topic_name.nil?
162
+ topic_name
163
+ else
164
+ topic_id
165
+ end
166
+ when :predefined
167
+ [topic_id].pack('n')
168
+ end
169
+ end
170
+
171
+ # Used where a field can either be a Topic Id or a Topic Name
172
+ # (the Subscribe and Unsubscribe packet types)
173
+ def parse_topic(topic)
174
+ case topic_id_type
175
+ when :normal
176
+ self.topic_name = topic
177
+ when :short
178
+ self.topic_name = topic
179
+ self.topic_id = topic
180
+ when :predefined
181
+ self.topic_id = topic.unpack('n').first
182
+ end
183
+ end
184
+
185
+ class Advertise < Packet
186
+ attr_accessor :gateway_id
187
+ attr_accessor :duration
188
+
189
+ DEFAULTS = {
190
+ :gateway_id => 0x00,
191
+ :duration => 0
192
+ }
193
+
194
+ def encode_body
195
+ [gateway_id, duration].pack('Cn')
196
+ end
197
+
198
+ def parse_body(buffer)
199
+ self.gateway_id, self.duration = buffer.unpack('Cn')
200
+ end
201
+ end
202
+
203
+ class Searchgw < Packet
204
+ attr_accessor :radius
205
+ DEFAULTS = {
206
+ :radius => 1
207
+ }
208
+
209
+ def encode_body
210
+ [radius].pack('C')
211
+ end
212
+
213
+ def parse_body(buffer)
214
+ self.radius, _ignore = buffer.unpack('C')
215
+ end
216
+ end
217
+
218
+ class Gwinfo < Packet
219
+ attr_accessor :gateway_id
220
+ attr_accessor :gateway_address
221
+ DEFAULTS = {
222
+ :gateway_id => 0,
223
+ :gateway_address => nil
224
+ }
225
+
226
+ def encode_body
227
+ [gateway_id,gateway_address].pack('Ca*')
228
+ end
229
+
230
+ def parse_body(buffer)
231
+ if buffer.length > 1
232
+ self.gateway_id, self.gateway_address = buffer.unpack('Ca*')
233
+ else
234
+ self.gateway_id, _ignore = buffer.unpack('C')
235
+ self.gateway_address = nil
236
+ end
237
+ end
238
+ end
239
+
240
+ class Connect < Packet
241
+ attr_accessor :keep_alive
242
+ attr_accessor :client_id
243
+
244
+ DEFAULTS = {
245
+ :request_will => false,
246
+ :clean_session => true,
247
+ :keep_alive => 15
248
+ }
249
+
250
+ # Get serialisation of packet's body
251
+ def encode_body
252
+ if @client_id.nil? or @client_id.length < 1 or @client_id.length > 23
253
+ raise "Invalid client identifier when serialising packet"
254
+ end
255
+
256
+ [encode_flags, 0x01, keep_alive, client_id].pack('CCna*')
257
+ end
258
+
259
+ def parse_body(buffer)
260
+ flags, protocol_id, self.keep_alive, self.client_id = buffer.unpack('CCna*')
261
+
262
+ if protocol_id != 0x01
263
+ raise ProtocolException.new("Unsupported protocol ID number: #{protocol_id}")
264
+ end
265
+
266
+ parse_flags(flags)
267
+ end
268
+ end
269
+
270
+ class Connack < Packet
271
+ attr_accessor :return_code
272
+
273
+ # Get a string message corresponding to a return code
274
+ def return_msg
275
+ case return_code
276
+ when 0x00
277
+ "Accepted"
278
+ when 0x01
279
+ "Rejected: congestion"
280
+ when 0x02
281
+ "Rejected: invalid topic ID"
282
+ when 0x03
283
+ "Rejected: not supported"
284
+ else
285
+ "Rejected: error code #{return_code}"
286
+ end
287
+ end
288
+
289
+ def encode_body
290
+ unless return_code.is_a?(Integer)
291
+ raise "return_code must be an Integer"
292
+ end
293
+
294
+ [return_code].pack('C')
295
+ end
296
+
297
+ def parse_body(buffer)
298
+ self.return_code = buffer.unpack('C')[0]
299
+ end
300
+ end
301
+
302
+ class Willtopicreq < Packet
303
+ # No attributes
304
+ end
305
+
306
+ class Willtopic < Packet
307
+ attr_accessor :topic_name
308
+
309
+ DEFAULTS = {
310
+ :qos => 0,
311
+ :retain => false,
312
+ :topic_name => nil
313
+ }
314
+
315
+ def encode_body
316
+ if topic_name.nil? or topic_name.empty?
317
+ ''
318
+ else
319
+ [encode_flags, topic_name].pack('Ca*')
320
+ end
321
+ end
322
+
323
+ def parse_body(buffer)
324
+ if buffer.length > 1
325
+ flags, self.topic_name = buffer.unpack('Ca*')
326
+ else
327
+ flags, _ignore = buffer.unpack('C')
328
+ self.topic_name = nil
329
+ end
330
+ parse_flags(flags)
331
+ end
332
+ end
333
+
334
+ class Willmsgreq < Packet
335
+ # No attributes
336
+ end
337
+
338
+ class Willmsg < Packet
339
+ attr_accessor :data
340
+
341
+ def encode_body
342
+ data
343
+ end
344
+
345
+ def parse_body(buffer)
346
+ self.data = buffer
347
+ end
348
+ end
349
+
350
+ class Register < Packet
351
+ attr_accessor :id
352
+ attr_accessor :topic_id
353
+ attr_accessor :topic_name
354
+
355
+ DEFAULTS = {
356
+ :id => 0x00,
357
+ :topic_id_type => :normal
358
+ }
359
+
360
+ def encode_body
361
+ unless id.is_a?(Integer)
362
+ raise "id must be an Integer"
363
+ end
364
+
365
+ unless topic_id.is_a?(Integer)
366
+ raise "topic_id must be an Integer"
367
+ end
368
+
369
+ [topic_id, id, topic_name].pack('nna*')
370
+ end
371
+
372
+ def parse_body(buffer)
373
+ self.topic_id, self.id, self.topic_name = buffer.unpack('nna*')
374
+ end
375
+ end
376
+
377
+ class Regack < Packet
378
+ attr_accessor :id
379
+ attr_accessor :topic_id
380
+ attr_accessor :return_code
381
+
382
+ DEFAULTS = {
383
+ :id => 0x00,
384
+ :topic_id => 0x00,
385
+ :topic_id_type => :normal
386
+ }
387
+
388
+ def encode_body
389
+ unless id.is_a?(Integer)
390
+ raise "id must be an Integer"
391
+ end
392
+
393
+ unless topic_id.is_a?(Integer)
394
+ raise "topic_id must be an Integer"
395
+ end
396
+
397
+ [topic_id, id, return_code].pack('nnC')
398
+ end
399
+
400
+ def parse_body(buffer)
401
+ self.topic_id, self.id, self.return_code = buffer.unpack('nnC')
402
+ end
403
+ end
404
+
405
+ class Publish < Packet
406
+ attr_accessor :topic_id
407
+ attr_accessor :id
408
+ attr_accessor :data
409
+
410
+ DEFAULTS = {
411
+ :id => 0x00,
412
+ :duplicate => false,
413
+ :qos => 0,
414
+ :retain => false,
415
+ :topic_id_type => :normal
416
+ }
417
+
418
+ def encode_body
419
+ unless id.is_a?(Integer)
420
+ raise "id must be an Integer"
421
+ end
422
+
423
+ [encode_flags, encode_topic_id, id, data].pack('Cnna*')
424
+ end
425
+
426
+ def parse_body(buffer)
427
+ flags, topic_id, self.id, self.data = buffer.unpack('Cnna*')
428
+ parse_flags(flags)
429
+ parse_topic_id(topic_id)
430
+ end
431
+ end
432
+
433
+ class Puback < Packet
434
+ attr_accessor :topic_id
435
+ attr_accessor :id
436
+ attr_accessor :return_code
437
+
438
+ DEFAULTS = {
439
+ :id => 0x00,
440
+ :topic_id => nil,
441
+ :return_code => 0x00,
442
+ }
443
+
444
+ def encode_body
445
+ unless id.is_a?(Integer)
446
+ raise "id must be an Integer"
447
+ end
448
+
449
+ unless topic_id.is_a?(Integer)
450
+ raise "topic_id must be an Integer"
451
+ end
452
+
453
+ [topic_id, id, return_code].pack('nnC')
454
+ end
455
+
456
+ def parse_body(buffer)
457
+ self.topic_id, self.id, self.return_code = buffer.unpack('nnC')
458
+ end
459
+ end
460
+
461
+ class Pubcomp < Packet
462
+ attr_accessor :id
463
+
464
+ DEFAULTS = {
465
+ :id => 0x00
466
+ }
467
+
468
+ def encode_body
469
+ unless id.is_a?(Integer)
470
+ raise "id must be an Integer"
471
+ end
472
+
473
+ [id].pack('n')
474
+ end
475
+
476
+ def parse_body(buffer)
477
+ self.id, _ignore = buffer.unpack('n')
478
+ end
479
+ end
480
+
481
+ class Pubrec < Packet
482
+ attr_accessor :id
483
+
484
+ DEFAULTS = {
485
+ :id => 0x00
486
+ }
487
+
488
+ def encode_body
489
+ unless id.is_a?(Integer)
490
+ raise "id must be an Integer"
491
+ end
492
+
493
+ [id].pack('n')
494
+ end
495
+
496
+ def parse_body(buffer)
497
+ self.id, _ignore = buffer.unpack('n')
498
+ end
499
+ end
500
+
501
+ class Pubrel < Packet
502
+ attr_accessor :id
503
+
504
+ DEFAULTS = {
505
+ :id => 0x00
506
+ }
507
+
508
+ def encode_body
509
+ unless id.is_a?(Integer)
510
+ raise "id must be an Integer"
511
+ end
512
+
513
+ [id].pack('n')
514
+ end
515
+
516
+ def parse_body(buffer)
517
+ self.id, _ignore = buffer.unpack('n')
518
+ end
519
+ end
520
+
521
+ class Subscribe < Packet
522
+ attr_accessor :id
523
+ attr_accessor :topic_id
524
+ attr_accessor :topic_name
525
+
526
+ DEFAULTS = {
527
+ :id => 0x00,
528
+ :topic_id_type => :normal
529
+ }
530
+
531
+ def encode_body
532
+ unless id.is_a?(Integer)
533
+ raise "id must be an Integer"
534
+ end
535
+
536
+ [encode_flags, id, encode_topic].pack('Cna*')
537
+ end
538
+
539
+ def parse_body(buffer)
540
+ flags, self.id, topic = buffer.unpack('Cna*')
541
+ parse_flags(flags)
542
+ parse_topic(topic)
543
+ end
544
+ end
545
+
546
+ class Suback < Packet
547
+ attr_accessor :id
548
+ attr_accessor :topic_id
549
+ attr_accessor :return_code
550
+
551
+ DEFAULTS = {
552
+ :qos => 0,
553
+ :id => 0x00,
554
+ :topic_id => 0x00,
555
+ :topic_id_type => :normal
556
+ }
557
+
558
+ def encode_body
559
+ unless id.is_a?(Integer)
560
+ raise "id must be an Integer"
561
+ end
562
+
563
+ [encode_flags, encode_topic_id, id, return_code].pack('CnnC')
564
+ end
565
+
566
+ def parse_body(buffer)
567
+ flags, topic_id, self.id, self.return_code = buffer.unpack('CnnC')
568
+ parse_flags(flags)
569
+ parse_topic_id(topic_id)
570
+ end
571
+ end
572
+
573
+ class Unsubscribe < Packet
574
+ attr_accessor :id
575
+ attr_accessor :topic_id
576
+ attr_accessor :topic_name
577
+
578
+ DEFAULTS = {
579
+ :id => 0x00,
580
+ :topic_id_type => :normal
581
+ }
582
+
583
+ def encode_body
584
+ unless id.is_a?(Integer)
585
+ raise "id must be an Integer"
586
+ end
587
+
588
+ [encode_flags, id, encode_topic].pack('Cna*')
589
+ end
590
+
591
+ def parse_body(buffer)
592
+ flags, self.id, topic = buffer.unpack('Cna*')
593
+ parse_flags(flags)
594
+ parse_topic(topic)
595
+ end
596
+ end
597
+
598
+ class Unsuback < Packet
599
+ attr_accessor :id
600
+
601
+ DEFAULTS = {
602
+ :id => 0x00,
603
+ }
604
+
605
+ def encode_body
606
+ unless id.is_a?(Integer)
607
+ raise "id must be an Integer"
608
+ end
609
+
610
+ [id].pack('n')
611
+ end
612
+
613
+ def parse_body(buffer)
614
+ self.id = buffer.unpack('n').first
615
+ end
616
+ end
617
+
618
+ class Pingreq < Packet
619
+ # No attributes
620
+ end
621
+
622
+ class Pingresp < Packet
623
+ # No attributes
624
+ end
625
+
626
+ class Disconnect < Packet
627
+ attr_accessor :duration
628
+
629
+ DEFAULTS = {
630
+ :duration => nil
631
+ }
632
+
633
+ def encode_body
634
+ if duration.nil? or duration == 0
635
+ ''
636
+ else
637
+ [duration].pack('n')
638
+ end
639
+ end
640
+
641
+ def parse_body(buffer)
642
+ if buffer.length == 2
643
+ self.duration = buffer.unpack('n').first
644
+ else
645
+ self.duration = nil
646
+ end
647
+ end
648
+ end
649
+
650
+ class Willtopicupd < Packet
651
+ attr_accessor :topic_name
652
+
653
+ DEFAULTS = {
654
+ :qos => 0,
655
+ :retain => false,
656
+ :topic_name => nil
657
+ }
658
+
659
+ def encode_body
660
+ if topic_name.nil? or topic_name.empty?
661
+ ''
662
+ else
663
+ [encode_flags, topic_name].pack('Ca*')
664
+ end
665
+ end
666
+
667
+ def parse_body(buffer)
668
+ if buffer.length > 1
669
+ flags, self.topic_name = buffer.unpack('Ca*')
670
+ parse_flags(flags)
671
+ else
672
+ self.topic_name = nil
673
+ end
674
+ end
675
+ end
676
+
677
+ class Willtopicresp < Packet
678
+ attr_accessor :return_code
679
+
680
+ DEFAULTS = {
681
+ :return_code => 0x00
682
+ }
683
+
684
+ def encode_body
685
+ unless return_code.is_a?(Integer)
686
+ raise "return_code must be an Integer"
687
+ end
688
+
689
+ [return_code].pack('C')
690
+ end
691
+
692
+ def parse_body(buffer)
693
+ self.return_code, _ignore = buffer.unpack('C')
694
+ end
695
+ end
696
+
697
+ class Willmsgupd < Packet
698
+ attr_accessor :data
699
+
700
+ def encode_body
701
+ data
702
+ end
703
+
704
+ def parse_body(buffer)
705
+ self.data = buffer
706
+ end
707
+ end
708
+
709
+ class Willmsgresp < Packet
710
+ attr_accessor :return_code
711
+
712
+ DEFAULTS = {
713
+ :return_code => 0x00
714
+ }
715
+
716
+ def encode_body
717
+ unless return_code.is_a?(Integer)
718
+ raise "return_code must be an Integer"
719
+ end
720
+
721
+ [return_code].pack('C')
722
+ end
723
+
724
+ def parse_body(buffer)
725
+ self.return_code, _ignore = buffer.unpack('C')
726
+ end
727
+ end
728
+
729
+ end
730
+
731
+
732
+ # An enumeration of the MQTT-SN packet types
733
+ PACKET_TYPES = {
734
+ 0x00 => MQTT::SN::Packet::Advertise,
735
+ 0x01 => MQTT::SN::Packet::Searchgw,
736
+ 0x02 => MQTT::SN::Packet::Gwinfo,
737
+ 0x04 => MQTT::SN::Packet::Connect,
738
+ 0x05 => MQTT::SN::Packet::Connack,
739
+ 0x06 => MQTT::SN::Packet::Willtopicreq,
740
+ 0x07 => MQTT::SN::Packet::Willtopic,
741
+ 0x08 => MQTT::SN::Packet::Willmsgreq,
742
+ 0x09 => MQTT::SN::Packet::Willmsg,
743
+ 0x0a => MQTT::SN::Packet::Register,
744
+ 0x0b => MQTT::SN::Packet::Regack,
745
+ 0x0c => MQTT::SN::Packet::Publish,
746
+ 0x0d => MQTT::SN::Packet::Puback,
747
+ 0x0e => MQTT::SN::Packet::Pubcomp,
748
+ 0x0f => MQTT::SN::Packet::Pubrec,
749
+ 0x10 => MQTT::SN::Packet::Pubrel,
750
+ 0x12 => MQTT::SN::Packet::Subscribe,
751
+ 0x13 => MQTT::SN::Packet::Suback,
752
+ 0x14 => MQTT::SN::Packet::Unsubscribe,
753
+ 0x15 => MQTT::SN::Packet::Unsuback,
754
+ 0x16 => MQTT::SN::Packet::Pingreq,
755
+ 0x17 => MQTT::SN::Packet::Pingresp,
756
+ 0x18 => MQTT::SN::Packet::Disconnect,
757
+ 0x1a => MQTT::SN::Packet::Willtopicupd,
758
+ 0x1b => MQTT::SN::Packet::Willtopicresp,
759
+ 0x1c => MQTT::SN::Packet::Willmsgupd,
760
+ 0x1d => MQTT::SN::Packet::Willmsgresp,
761
+ }
762
+
763
+ end