Class: Dap::Filter::FilterDecodeBacnetRPMReply
- Inherits:
-
Object
- Object
- Dap::Filter::FilterDecodeBacnetRPMReply
- Includes:
- BaseDecoder
- Defined in:
- lib/dap/filter/udp.rb
Overview
Decode a BACnet Read Property Multiple reply
Constant Summary collapse
- TAG_TYPE_LENGTHS =
{ 2 => 2, 10 => 4, 11 => 4, }
Instance Attribute Summary
Attributes included from Base
Instance Method Summary collapse
Methods included from BaseDecoder
Methods included from Base
Instance Method Details
#decode(sdata) ⇒ Object
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 |
# File 'lib/dap/filter/udp.rb', line 379 def decode(sdata) info = {} return if sdata.length < 9 data = sdata.dup bacnet_vlc_type, bacnet_vlc_function, bacnet_vlc_length = data.slice!(0,4).unpack("CCn") # if this isn't a BACnet/IP (0x81) original unicast NPDU (0x0a), abort if bacnet_vlc_type != 0x81 || bacnet_vlc_function != 0x0a return info else info['bacnet_vlc_type'] = bacnet_vlc_type info['bacnet_vlc_function'] = bacnet_vlc_function info['bacnet_vlc_length'] = bacnet_vlc_length end # we only know how to decode version 1, so abort if it is anything else # but store the version in the event that we want to parse these later bacnet_npdu_version, bacnet_npdu_control = data.slice!(0,2).unpack("CC") info['bacnet_npdu_version'] = bacnet_npdu_version info['bacnet_npdu_control'] = bacnet_npdu_control return info if bacnet_npdu_version != 1 bacnet_apdu_type_flags, bacnet_apdu_invoke_id, bacnet_apdu_service_choice = data.slice!(0,3).unpack("CCC") bacnet_apdu_type = bacnet_apdu_type_flags >> 4 bacnet_apdu_flags = bacnet_apdu_type_flags & 0b00001111 info['bacnet_apdu_type'] = bacnet_apdu_type info['bacnet_apdu_flags'] = bacnet_apdu_flags info['bacnet_apdu_invoke_id'] = bacnet_apdu_invoke_id info['bacnet_apdu_service_choice'] = bacnet_apdu_service_choice return info unless (bacnet_apdu_type == 3 && bacnet_apdu_service_choice == 14) return info unless data.size > 5 # XXX: don't know what to do with this right now bacnet_object_id = data.slice!(0,5) return info unless data.slice!(0,1).unpack('C').first == 0x1e props = {} # XXX: I think this is ASN.1, but still need to confirm while (true) do #puts "size is #{data.size}, data is #{data.each_byte.map { |b| b.to_s(16) }.join(' ')}" break if data.size < 4 property_tag, property_id = data.slice!(0,2).unpack('CC') props[property_id] = true # slice off the opening tag otag = data.slice!(0,1).unpack('C').first if otag == 0x5e data.slice!(0,5) #puts "Property #{property_id} unknown" props[property_id] = nil else # it isn't clear if the length is one byte wide followed by one byte of # 0x00 for spacing or if it is two bytes little endian. Looks like the later. # XXX? tag_flags = data.slice!(0,1).unpack('C').first tag_type = tag_flags >> 4 if TAG_TYPE_LENGTHS.key?(tag_type) #puts "Know how to handle property #{property_id}'s tag type #{tag_type}" props[property_id] = data.slice!(0, TAG_TYPE_LENGTHS[tag_type]) else if tag_type == 7 property_length = data.slice!(0,2).unpack('v').first #puts "Handled property #{property_id}'s #{property_length}-byte tag type #{tag_type}" property_length -= 1 # handle String props[property_id] = data.slice!(0, property_length) else #puts "Don't know how to handle property #{property_id}'s tag type #{tag_type}" end end ctag = data.slice!(0,1).unpack('C') end if data.size == 0 #puts "done" break else #puts "going" end end props.each do |k,v| info[k] = v end info end |