///|
pub(all) struct ReadAccess {
object : ObjectId
properties : Array[(UInt32, UInt32?)]
} derive(Debug)
///|
pub(all) enum ReadResult {
PropertyData(PropertyRef, Array[Tag])
PropertyFailure(PropertyRef, UInt32, UInt32)
} derive(Debug)
///|
pub(all) struct ReadAccessResult {
object : ObjectId
results : Array[ReadResult]
} derive(Debug)
///|
pub fn encode_read_multiple(
access : Array[ReadAccess],
limits~ : Limits = Limits::default(),
) -> Bytes raise BacnetError {
let tags : Array[Tag] = []
if access.is_empty() {
raise Invalid("empty read access list", 0)
}
for entry in access {
if entry.properties.is_empty() {
raise Invalid("empty property references", 0)
}
let children : Array[Tag] = []
for (property, index) in entry.properties {
children.push(context_uint(0, property))
if index is Some(i) {
children.push(context_uint(1, i))
}
}
tags.push(context_object(0, entry.object))
tags.push(Constructed(1, children))
}
encode_tags(tags, limits~)
}
///|
pub fn decode_read_multiple(
bytes : Bytes,
limits~ : Limits = Limits::default(),
) -> Array[ReadAccess] raise BacnetError {
let f = Fields::new(decode_tags(bytes, limits~))
let result : Array[ReadAccess] = []
while f.pos < f.tags.length() {
let object = f.object(0)
let children = Fields::new(f.children(1))
let properties : Array[(UInt32, UInt32?)] = []
while children.pos < children.tags.length() {
let property = children.uint(0)
let index = children.optional_uint(1)
properties.push((property, index))
}
if properties.is_empty() {
raise Invalid("empty property references", f.pos)
}
result.push({ object, properties, })
}
if result.is_empty() {
raise Invalid("empty read access list", 0)
}
result
}
///|
pub fn encode_multiple_ack(
access : Array[ReadAccessResult],
limits~ : Limits = Limits::default(),
) -> Bytes raise BacnetError {
let tags : Array[Tag] = []
if access.is_empty() {
raise Invalid("empty access results", 0)
}
for entry in access {
let children : Array[Tag] = []
for result in entry.results {
let (reference, choice) = match result {
PropertyData(reference, value) => (reference, Constructed(4, value))
PropertyFailure(reference, class, code) =>
(
reference,
Constructed(5, [
Application(Enumerated(class)),
Application(Enumerated(code)),
]),
)
}
if reference.object != entry.object {
raise Invalid("access object mismatch", 0)
}
children.push(context_uint(2, reference.property))
if reference.index is Some(index) {
children.push(context_uint(3, index))
}
children.push(choice)
}
if children.is_empty() {
raise Invalid("empty result list", 0)
}
tags.push(context_object(0, entry.object))
tags.push(Constructed(1, children))
}
encode_tags(tags, limits~)
}
///|
pub fn decode_multiple_ack(
bytes : Bytes,
limits~ : Limits = Limits::default(),
) -> Array[ReadAccessResult] raise BacnetError {
let f = Fields::new(decode_tags(bytes, limits~))
let output : Array[ReadAccessResult] = []
while f.pos < f.tags.length() {
let object = f.object(0)
let children = Fields::new(f.children(1))
let results : Array[ReadResult] = []
while children.pos < children.tags.length() {
let property = children.uint(2)
let index = children.optional_uint(3)
let reference : PropertyRef = { object, property, index, }
match children.next() {
Constructed(4, value) => results.push(PropertyData(reference, value))
Constructed(5, error) =>
match error[:] {
[Application(Enumerated(class)), Application(Enumerated(code))] =>
results.push(PropertyFailure(reference, class, code))
_ => raise Invalid("property access error fields", children.pos)
}
_ => raise Invalid("property access result choice", children.pos)
}
}
if results.is_empty() {
raise Invalid("empty result list", f.pos)
}
output.push({ object, results, })
}
if output.is_empty() {
raise Invalid("empty access results", 0)
}
output
}
///|
pub extend ReadAccess with @debug.Debug::{to_repr}
///|
pub extend ReadResult with @debug.Debug::{to_repr}
///|
pub extend ReadAccessResult with @debug.Debug::{to_repr}