///|
/// A named request in a batch operation.
pub(all) struct BatchItem {
id : Int
request : Frame
}
///|
pub fn BatchItem::new(
id : Int,
request : Frame,
) -> Result[BatchItem, ModbusError] {
if id < 0 {
Err(InvalidData)
} else {
Ok({ id, request })
}
}
///|
/// An ordered batch plan used to pipeline independent requests.
pub struct BatchPlan {
items : Array[BatchItem]
max_items : Int
}
///|
pub fn BatchPlan::new(max_items? : Int = 128) -> Result[BatchPlan, ModbusError] {
if max_items < 1 {
Err(CapacityExceeded)
} else {
Ok({ items: [], max_items })
}
}
///|
pub fn BatchPlan::add(
self : BatchPlan,
item : BatchItem,
) -> Result[Unit, ModbusError] {
if self.items.length() >= self.max_items {
return Err(CapacityExceeded)
}
for current in self.items {
if current.id == item.id {
return Err(InvalidData)
}
}
match validate_frame(item.request, false) {
Ok(_) => {
self.items.push(item)
Ok(())
}
Err(error) => Err(error)
}
}
///|
pub fn BatchPlan::length(self : BatchPlan) -> Int {
self.items.length()
}
///|
pub fn BatchPlan::item(
self : BatchPlan,
index : Int,
) -> Result[BatchItem, ModbusError] {
if index < 0 || index >= self.items.length() {
Err(InvalidAddress)
} else {
Ok(self.items[index])
}
}
///|
pub fn BatchPlan::snapshot(self : BatchPlan) -> Array[BatchItem] {
let out : Array[BatchItem] = []
for item in self.items {
out.push(item)
}
out
}
///|
/// The result of executing one batch item.
pub(all) enum BatchResult {
Completed(Int, Frame)
Failed(Int, ModbusError)
}
///|
/// Execute an ordered plan against a deterministic device.
pub fn BatchPlan::execute(
self : BatchPlan,
device : Device,
) -> Array[BatchResult] {
let out : Array[BatchResult] = []
for item in self.items {
match device.handle(item.request) {
Ok(response) => out.push(Completed(item.id, response))
Err(error) => out.push(Failed(item.id, error))
}
}
out
}
///|
pub fn batch_completed(results : Array[BatchResult]) -> Int {
let mut count = 0
for result in results {
if result is Completed(_, _) {
count += 1
}
}
count
}
///|
pub fn batch_failed(results : Array[BatchResult]) -> Int {
results.length() - batch_completed(results)
}
///|
/// Merge successful register responses from a batch into one ordered array.
pub fn batch_register_values(
results : Array[BatchResult],
) -> Result[Array[UInt16], ModbusError] {
let out : Array[UInt16] = []
for result in results {
match result {
Completed(_, frame) =>
match frame.pdu.data.length() {
0 => ()
_ => {
let values = if frame.pdu.data[0].to_int() ==
frame.pdu.data.length() - 1 {
let bytes : Array[Byte] = []
for index in 1..
for item in items {
out.push(item)
}
Err(error) => return Err(error)
}
}
}
Failed(_, error) => return Err(error)
}
}
Ok(out)
}