Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/jtroo/bacnet_parse
#![no_std] BACnet protocol parsing
https://github.com/jtroo/bacnet_parse
bacnet no-std parser protocol
Last synced: 3 months ago
JSON representation
#![no_std] BACnet protocol parsing
- Host: GitHub
- URL: https://github.com/jtroo/bacnet_parse
- Owner: jtroo
- License: mpl-2.0
- Created: 2019-11-24T07:01:05.000Z (about 5 years ago)
- Default Branch: master
- Last Pushed: 2020-07-11T08:55:45.000Z (over 4 years ago)
- Last Synced: 2024-10-06T09:35:09.844Z (4 months ago)
- Topics: bacnet, no-std, parser, protocol
- Language: Rust
- Homepage:
- Size: 71.3 KB
- Stars: 3
- Watchers: 2
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# bacnet_parse
[![LICENSE](https://img.shields.io/badge/license-MPL_2.0-blue.svg)](LICENSE)
[![Crates.io Version](https://img.shields.io/crates/v/bacnet_parse.svg)](https://crates.io/crates/bacnet_parse)## bacnet_parse is a #![no_std] library to parse BACnet bytes into read-only data structures
Currently handles:
* MS/TP
* BVLL (basic - just enough to get NPDU)
* NPDUTargeting support for:
* NSDU ([NLM/RPDU](http://www.bacnetwiki.com/wiki/index.php?title=Network_Layer_Message_Type), APDU)To assist parsing BACnet IP or BACnet Ethernet, two recommended libraries are:
* [pnet](https://crates.io/crates/pnet)
* [etherparse](https://crates.io/crates/etherparse)### How to use this library
For BACnet ethernet and BACnet IP, first identify your BACnet application layer bytes then call
to `parse_bvlc(bytes)` and go from there.For MSTP, call either `parse_mstp(bytes)` or `parse_mstp_skip_crc_compute(bytes)`.
Not yet implemented below:
In order to parse the RPDU or APDU, first check which one you have with `npdu.is_apdu()` then
call either `parse_apdu(npdu.payload())` or `parse_rpdu(npdu.payload())`.### Examples
BVLC example
```rust
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 example
```rust
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(5));
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);
```### Why not use [nom](https://crates.io/crates/nom)?
nom is a great library, but I don't think it's well suited to application layer data with weird
formats like BACnet. For example, the weirdness of the NPDU layout where the hop count value's
existence is tied to but may or may not be contiguous with the destination port/address.Avoiding the use of nom may also lower the barrier to entry for contribution so that a
potential contributor does not also need to learn the nom library.These are opinions, so if you disagree and would like to use nom for parsing, feel free to make
a pull request that includes nom.License: MPL-2.0