///|
fn Device::handle_read_file_record(
self : Device,
request : Frame,
) -> Result[Frame, ModbusError] {
let references = match parse_file_references(request.pdu.data) {
Ok(value) => value
Err(error) => return Err(error)
}
let payload : Array[Byte] = [0]
let mut total = 0
for reference in references {
let values = match self.file_store.get(reference) {
Ok(value) => value
Err(error) => return Err(error)
}
let sub_length = 1 + values.length() * 2
total += sub_length
if total > 252 {
return Err(InvalidLength)
}
payload.push(reference.reference_type)
for value in values {
payload.push((value >> 8).to_byte())
payload.push(value.to_byte())
}
}
payload[0] = total.to_byte()
Ok(response_frame(request, payload))
}
///|
fn Device::handle_write_file_record(
self : Device,
request : Frame,
) -> Result[Frame, ModbusError] {
let records = match parse_file_writes(request.pdu.data) {
Ok(value) => value
Err(error) => return Err(error)
}
for record in records {
match self.file_store.put(record) {
Ok(_) => ()
Err(error) => return Err(error)
}
}
Ok(response_frame(request, copy_bytes(request.pdu.data)))
}
///|
fn parse_file_references(
data : Array[Byte],
) -> Result[Array[FileRecordReference], ModbusError] {
if data.length() < 8 ||
data[0].to_int() != data.length() - 1 ||
(data.length() - 1) % 7 != 0 {
return Err(InvalidLength)
}
let out : Array[FileRecordReference] = []
let count = (data.length() - 1) / 7
for index in 0.. out.push(reference)
Err(error) => return Err(error)
}
}
Ok(out)
}
///|
fn parse_file_writes(
data : Array[Byte],
) -> Result[Array[FileRecordWrite], ModbusError] {
if data.length() < 9 || data[0].to_int() != data.length() - 1 {
return Err(InvalidLength)
}
let out : Array[FileRecordWrite] = []
let mut offset = 1
while offset < data.length() {
if offset + 7 > data.length() || data[offset] != 6 {
return Err(InvalidData)
}
let file_number = (data[offset + 1].to_uint16() << 8) |
data[offset + 2].to_uint16()
let record_number = (data[offset + 3].to_uint16() << 8) |
data[offset + 4].to_uint16()
let record_length = (data[offset + 5].to_uint16() << 8) |
data[offset + 6].to_uint16()
let value_bytes = record_length.to_int() * 2
if offset + 7 + value_bytes > data.length() {
return Err(Incomplete)
}
let values : Array[UInt16] = []
for index in 0.. value
Err(error) => return Err(error)
}
match FileRecordWrite::new(reference, values) {
Ok(value) => out.push(value)
Err(error) => return Err(error)
}
offset += 7 + value_bytes
}
Ok(out)
}