///|
/// Return whether a frame can be represented by a mode's ADU limit.
pub fn fits_mode_limit(mode : Mode, frame : Frame) -> Bool {
encoded_length(mode, frame) <= limits_for(mode).max_adu
}
///|
/// Return the number of data bytes available after transport framing.
pub fn mode_payload_capacity(mode : Mode) -> Int {
match mode {
Rtu => limits_for(mode).max_adu - 4
Ascii => (limits_for(mode).max_adu - 7) / 2 - 2
Tcp => limits_for(mode).max_adu - 8
}
}
///|
pub fn validate_mode_payload(
mode : Mode,
data_length : Int,
) -> Result[Unit, ModbusError] {
if data_length < 1 || data_length > mode_payload_capacity(mode) {
Err(InvalidLength)
} else {
Ok(())
}
}
///|
/// Return a conservative maximum request size for a function and mode.
pub fn max_request_adu(mode : Mode, function : Byte) -> Int {
let payload = match function {
1 | 2 => 4
3 | 4 => 4
5 | 6 => 4
15 => 253
16 => 251
20 => 246
21 => 253
22 => 6
23 => 251
43 => 253
_ => 252
}
match mode {
Rtu => payload + 4
Ascii => 7 + (payload + 2) * 2
Tcp => payload + 8
}
}
///|
/// Calculate the number of frames needed for a logical register read.
pub fn frame_count_for_registers(quantity : Int) -> Result[Int, ModbusError] {
if quantity < 1 {
Err(InvalidQuantity)
} else {
Ok((quantity + 124) / 125)
}
}
///|
/// Calculate the number of frames needed for a logical coil read.
pub fn frame_count_for_coils(quantity : Int) -> Result[Int, ModbusError] {
if quantity < 1 {
Err(InvalidQuantity)
} else {
Ok((quantity + 1999) / 2000)
}
}
///|
/// Check whether a write payload is legal before allocating its data array.
pub fn validate_write_shape(
function : Byte,
quantity : Int,
) -> Result[Unit, ModbusError] {
let limit = write_quantity_limit(function)
if limit == 0 {
Err(InvalidFunction)
} else if quantity < 1 || quantity > limit {
Err(InvalidQuantity)
} else {
Ok(())
}
}
///|
/// Check that an entire sequence stays below a caller's queue budget.
pub fn fits_queue_budget(
frames : Array[Frame],
mode : Mode,
budget : Int,
) -> Bool {
if budget < 0 {
return false
}
let mut used = 0
for frame in frames {
used += encoded_length(mode, frame)
}
used <= budget
}