Typed BACnet/IP object property services and bounded device application core
moon check --target all --deny-warn
moon build --target all --deny-warn
moon test --target all --deny-warn
moon run examples/hvac --target native --deny-warn
moon run examples/energy --target native --deny-warn
moon run examples/monitoring --target js --deny-warn
moon run examples/scale --target native --deny-warn& .\tools\windows\moon.ps1 test --target all --deny-warn
& .\tools\windows\moon.ps1 run examples/hvac --target native --deny-warnmoon add erzhuzi259/moonbacnet@0.1.0import { "erzhuzi259/moonbacnet" @bac, }
pkgtype(kind: "executable")fn main raise {
let device = @bac.Device::new(42, "room-controller", 999U)
let id = @bac.ObjectId::new(2, 1) // analog-value
device.add_point(id, "setpoint", Analog, Real(19.0F), commandable=true)
let server = @bac.Server::new(device)
let client = @bac.Client::new()
let body = @bac.encode_write_property({
reference: { object: id, property: 85U, index: None },
value: [Application(Real(23.0F))], priority: Some(8),
})
let tx = client.start("device", 15, body, 0UL)
let reply = server.datagram(tx.bytes, "client", 0UL).unwrap()
assert_true(client.receive("device", @bac.decode_datagram(reply), 0UL)
is Some(Completed(SimpleAck(_, 15))))
assert_eq(device.active_priority(id), Some(8))
}| 层次 | 已实现 | 首版边界 |
|---|---|---|
| 应用值 | null/bool/uint32/int32/REAL/DOUBLE/octet/string/bits/enum/date/time/object-id,精确位模式,嵌套context | 字符串仅encoding0 UTF-8;日期使用1900年偏移和协议通配字节,不提供日历运算 |
| 标签 | 扩展tag、8/16/32位长度、opening/closing、严格截断/计数/深度检查 | 未知application tag明确拒绝;编码规范化整数宽度,不保留原输入的非最短形式 |
| 网络报文 | IPv4 BVLC 原始单播/广播、forwarded、distribute、result、foreign-register;NPDU路由字段 | 只编解码相关包;没有BBMD表、外来设备注册管理、路由器、MS/TP、IPv6或BACnet/SC |
| APDU | 未分段confirmed/unconfirmed、simple/complex ACK、error/reject/abort | 分段及SegmentACK明确拒绝;设备宿主最多1476字节APDU,按请求方最大长度返回有界abort |
| 服务 | Who-Is/I-Am、ReadProperty、WriteProperty、ReadPropertyMultiple、SubscribeCOV、unconfirmed COV notification | RPM支持all(8)展开,required/optional宏未实现;不支持WritePropertyMultiple等其他服务 |
| 属性库 | 对象ID/名称唯一、Object_List/Property_List、数组索引、标量及只读自定义数组、类型与预算检查 | 索引0为数组长度,None为整体;远端数组及compound写入未实现;对象集合不经网络创建 |
| 测点 | analog/binary/multi-state input/output/value,类型域、Status_Flags、Out_Of_Service | 为明确子集对象模型,未实现标准对象的所有必备属性/行为;不是完整可认证设备profile |
| 控制 | 16级在途命令槽、默认priority16、Null释放、relinquish default、域检查 | priority6保留,网络写入拒绝;未实现输出最小开/关时间及优先级6内部计时;默认值由宿主API设置 |
| COV | 初始快照、累计模拟量阈值、二进制/状态变化、续期/取消/过期、原子poll | 只接受unconfirmed通知订阅;0 lifetime代表不定期,取消为两个可选字段均缺失;无通知持久重发 |
| 事务 | 按peer关联invoke/service/reference、轮转ID、超时/定次重试/取消 | 无网络socket;重复写入的业务幂等性仍由宿主决定;RPM客户端校验结构与service,不实现完整请求结果集合证明 |
moon build --target native --deny-warn
python -m pip install --target _local/oracle -r scripts/requirements-interop.txt
python scripts/interop.py
moon run cmd/main --target native -- tags INPUT.bin NEW_OUTPUT.bin
moon run cmd/main --target native -- rp INPUT.bin NEW_OUTPUT.binpub suberror BacnetError {
Invalid(String, Int)
Unsupported(String)
Limit(String)
State(String)
Property(UInt, UInt)
} derive(Debug)pub(all) enum Bvlc {
ResultCode(Int)
RegisterForeign(Int)
OriginalUnicast(Bytes)
OriginalBroadcast(Bytes)
Forwarded(Bytes, Bytes)
DistributeBroadcast(Bytes)
} derive(Debug)pub struct Client {
// private fields
}fn Client::receive(self : Client, peer : String, response : Apdu, now : UInt64) -> Completion? raise BacnetErrorfn Client::start(self : Client, peer : String, service : Int, body : Bytes, now : UInt64, max_apdu? : Int) -> Transmission raise BacnetErrorpub struct CovManager {
// private fields
}fn CovManager::subscribe(self : CovManager, peer : String, request : SubscribeCov, now : UInt64) -> Unit raise BacnetErrorpub(all) struct CovNotification {
process : UInt
device : ObjectId
object : ObjectId
remaining : UInt
values : Array[CovProperty]
} derive(Debug)pub struct Device {
// private fields
}fn Device::add_point(self : Device, id : ObjectId, name : String, domain : CommandDomain, initial : Value, commandable? : Bool, units? : UInt) -> Unit raise BacnetErrorfn Device::new(instance : Int, name : String, vendor : UInt, limits? : Limits) -> Device raise BacnetErrorfn Device::set_relinquish_default(self : Device, id : ObjectId, value : Value) -> Unit raise BacnetErrorfn Device::update(self : Device, id : ObjectId, property : UInt, value : Value) -> Unit raise BacnetErrorpub(all) struct DiscoveredDevice {
peer : String
announcement : IAm
first_seen : UInt64
last_seen : UInt64
}pub struct DiscoveryDirectory {
// private fields
}fn DiscoveryDirectory::expire(self : DiscoveryDirectory, now : UInt64, max_age : UInt64) -> Array[DiscoveredDevice] raise BacnetErrorfn DiscoveryDirectory::observe(self : DiscoveryDirectory, peer : String, announcement : IAm, now : UInt64) -> Bool raise BacnetErrorpub struct PriorityArray {
// private fields
}fn PriorityArray::write(self : PriorityArray, priority : Int, value : Value) -> Unit raise BacnetErrorpub(all) enum ReadResult {
PropertyData(PropertyRef, Array[Tag])
PropertyFailure(PropertyRef, UInt, UInt)
} derive(Debug)pub(all) struct Request {
invoke : Int
service : Int
max_apdu : Int
max_segments : Int
segmented_response_accepted : Bool
body : Bytes
} derive(Debug)pub struct Server {
// private fields
}fn Server::datagram(self : Server, bytes : Bytes, peer : String, now : UInt64) -> Bytes? raise BacnetErrorfn Server::handle(self : Server, apdu : Apdu, peer : String, now : UInt64) -> Apdu? raise BacnetErrorpub(all) struct WriteProperty {
reference : PropertyRef
value : Array[Tag]
priority : Int?
} derive(Debug)fn decode_multiple_ack(bytes : Bytes, limits? : Limits) -> Array[ReadAccessResult] raise BacnetErrorfn encode_multiple_ack(access : Array[ReadAccessResult], limits? : Limits) -> Bytes raise BacnetErrorInstall
Download zipTyped BACnet/IP object property services and bounded device application core