3 个版本 (破坏性更新)
0.3.0 | 2024 年 5 月 11 日 |
---|---|
0.2.0 | 2023 年 11 月 24 日 |
0.1.0 | 2023 年 11 月 16 日 |
314 在 嵌入式开发 中排名
每月下载量 170
240KB
6.5K SLoC
嵌入式 Bacnet
"愿我永不完美。愿我永不满足。愿我永不完美。" —— 查克·帕拉尼科,《搏击俱乐部》
这是一个用于嵌入式设备读取和写入 BACnet 报文的 Rust 库。BACnet 是一种用于建筑自动化和控制的协议。官方规范不幸地被付费墙挡住,因此这个实现是通过交叉引用多个代码实现拼凑而成的。我找到的最全面的实现和文档在这里:https://bacnet.sourceforge.net/,我对此非常感激。这也是一个好资源:http://www.bacnetwiki.com/wiki/
您可以使用此库发送和接收 BACnet 报文。但是,尚未实现整个规范,仅实现了我认为最重要的部分。如果您需要全面实现,请使用上述链接。
此库不需要标准库或内存分配器,因此当您解码网络报文时,请预期将使用迭代器和循环。
工作原理
BACnet 是一种可以在许多传输协议之上工作的协议。此实现仅与使用 UDP 报文的 BACnet IP 一起工作。像许多协议一样,这个也有层。一个应用层包裹在网络层中,网络层包裹在数据链路层中,数据链路层包裹在 UDP 报文中。如下所示
UdpPacket
|
-> DataLink (about the connection)
|
-> NetworkPdu (flags and the reason for the message)
|
-> ApplicationPdu (the payload)
其中 Pdu 代表协议数据单元。
这是一个典型的 BACnet 客户端使用此库的方式:向标准的 BACnet 端口发送老式的广播 UDP 报文,并监听同一端口的回复。这是使用未确认的 who_is
pdu(协议数据单元)完成的。当通过解码不可避免的 i_am
未确认响应找到控制器时,客户端可以发送 UDP 报文直接到该控制器。一个典型的请求可能是一个已确认的 property_read
pdu,以从控制器获取对象列表。已确认请求带有标识符,以便控制器可以响应发送的确切请求。
为什么要构建这个
我对所有的缩写和假设的已知知识感到沮丧,并希望制作一个初学者更容易使用的工具。例如,我会倾向于使用冗长的文件名,如 read_property.rs
而不是 rp.c
。我假设用户会使用带有自动完成的语言服务器,如 rust-analyzer
。现有的 Rust 实现似乎已被放弃,而现代 Rust 的功能提供了新的建模选项,因此这个库采用了相当不同的方法。
设计理念
我希望制作一个易于导航的库。因此,我选择不使用特质来抽象事物,因为在大多数情况下这并不必要,我真的讨厌导航的黑洞。代码布局应该尽可能清晰,您不需要阅读整个代码库就能找到您想要做的事情。
关于参考 C 实现的说明
以下说明适用于以下位置的 C 代码库:https://bacnet.sourceforge.net/ 我发现最重要的部分是位于 src/bacnet/basic/service
文件夹中,该文件夹处理堆栈的应用部分。使用的缩写有一些意义。例如,h_rpm.c
表示 handle_read_property_multiple
,用于编码和解码 read_property_multiple 确认请求。此外,h_rpm_a.c
表示 handle_read_property_multiple_acknowledgements
,用于编码和解码对上述请求的响应。
单元测试
当我有更多时间时,将会提供单元测试。请暂时使用示例。
了解内部结构
这个库的核心是一个 bacnet 编码器/解码器。因为它不分配内存,并且我们必须处理不同数量的事物(例如,一个 bacnet 报文可以包含任何数量的对象),编码和解码部分有不同的表示。例如,如果您想要编码对象列表,您将从一个容器传递一个切片,因为您事先知道要包含在报文中的对象数量。在解码事物列表时,我们使用迭代器,以便用户可以将这些对象收集到向量中,或者简单地即时处理它们。在内部,这表示为一个读取器,它可以从字节数据缓冲区中即时解码对象。
依赖项
~46–305KB