3 个不稳定版本
0.2.0 | 2019 年 11 月 30 日 |
---|---|
0.1.1 | 2019 年 11 月 25 日 |
0.1.0 | 2019 年 11 月 24 日 |
#9 在 #apdu
78KB
2K SLoC
bacnet_parse
bacnet_parse 是一个 #![no_std] 库,用于将 BACnet 字节解析到只读数据结构中
目前处理
- MS/TP
- BVLL(基本 - 只需足够的 NPDU)
- NPDU
目标支持
- NSDU(NLM/RPDU,APDU)
为了帮助解析 BACnet IP 或 BACnet 以太网,推荐使用以下两个库:
如何使用此库
对于 BACnet 以太网和 BACnet IP,首先确定您的 BACnet 应用层字节,然后调用 parse_bvlc(bytes)
并继续操作。
对于 MSTP,调用 parse_mstp(bytes)
或 parse_mstp_skip_crc_compute(bytes)
。
以下尚未实现
为了解析 RPDU 或 APDU,首先使用 npdu.is_apdu()
检查您拥有哪一个,然后调用 parse_apdu(npdu.payload())
或 parse_rpdu(npdu.payload())
。
示例
BVLC 示例
let bytes: &[u8] = &[
0x81, 0x0a, 0x00, 0x1b, // BVLC
0x01, 0x20, 0x00, 0x0d, 0x01, 0x3d, 0xff, // NPDU
0x30, 0xc9, 0x0c, 0x0c, 0x02, 0x00, 0x00, 0x6f, 0x19, 0x4c, 0x29, 0x00, 0x3e, 0x21,
0x21, 0x3f, // APDU
];
let bvlc = parse_bvlc(&bytes)?;
assert_eq!(bvlc.bvlc_function(), BVLCFunction::UnicastNPDU);
let npdu = bvlc.npdu().as_ref().expect("npdu");
assert_eq!(npdu.ncpi_control(), 0x20);
assert_eq!(npdu.is_apdu(), true);
assert_eq!(npdu.is_src_spec_present(), false);
assert_eq!(npdu.is_dst_spec_present(), true);
assert_eq!(npdu.is_expecting_reply(), false);
assert_eq!(npdu.src().is_none(), true);
let dst_hopcount = npdu.dst_hopcount().as_ref().expect("dst_hopcount");
assert_eq!(dst_hopcount.hopcount(), 255);
let dst = dst_hopcount.dst();
assert_eq!(dst.net(), 13);
assert_eq!(dst.addr().len(), 1);
assert_eq!(dst.addr()[0], 61);
MSTP 示例
let bytes: &[u8] = &[
0x55, 0xff, 0x05, 0x0c, 0x7f, 0x00, 0x1f, 0x35, 0x01, 0x0c, 0x00, 0x01, 0x06, 0xc0,
0xa8, 0x01, 0x12, 0xba, 0xc0, 0x02, 0x01, 0x6a, 0x0f, 0x0c, 0x00, 0x80, 0x00, 0x0a,
0x19, 0x55, 0x3e, 0x44, 0x41, 0xe8, 0x00, 0x01, 0x3f, 0x49, 0x09, 0xc9, 0x6f,
];
let frame = parse_mstp(bytes)?;
let (actual, expected) = frame.crcs().header();
assert_eq!(actual, expected);
assert_eq!(actual, 0x35);
let (actual, expected) = frame.crcs().data();
assert_eq!(actual, expected);
assert_eq!(actual, 0x6fc9);
assert_eq!(frame.frame_type(), MSTPFrameType::BACnetDataExpectingReply);
let npdu = frame.npdu().as_ref().expect("npdu");
let src = npdu.src().as_ref().expect("src");
assert_eq!(src.net(), 1);
assert_eq!(src.addr().len(), 6);
let addr_cmp: &[u8] = &[0xc0, 0xa8, 0x01, 0x12, 0xba, 0xc0];
assert_eq!(src.addr(), addr_cmp);
assert_eq!(npdu.dst_hopcount().is_none(), true);
let bytes: &[u8] = &[
0x55, 0xff, 0x05, 0x0c, 0x7f, 0x00, 0x1f, 0x34, 0x01, 0x0c, 0x00, 0x01, 0x06, 0xc0,
0xa8, 0x01, 0x12, 0xba, 0xc0, 0x02, 0x01, 0x6a, 0x0f, 0x0c, 0x00, 0x80, 0x00, 0x0a,
0x19, 0x55, 0x3e, 0x44, 0x41, 0xe8, 0x00, 0x01, 0x3f, 0x49, 0x09, 0xc9, 0x6e,
];
let frame = parse_mstp(bytes)?;
let (actual, expected) = frame.crcs().header();
assert_ne!(actual, expected);
assert_eq!(actual, 0x34);
let (actual, expected) = frame.crcs().data();
assert_ne!(actual, expected);
assert_eq!(actual, 0x6ec9);
为什么不使用 nom?
nom 是一个很棒的库,但我认为它不适合像 BACnet 这样具有奇怪格式的应用层数据。例如,NPDU 布局中的奇怪之处,其中跳数值的存在与目的端口/地址的连续性有关,但可能不是连续的。
避免使用 nom 也可能降低入门门槛,以便潜在的贡献者不需要学习 nom 库。
这些是意见,如果您不同意并希望使用nom进行解析,请随意提交包含nom的pull request。
许可证:MPL-2.0