///|
/// IOD Read Request Header.
pub(all) struct IODReadReqHeader {
seq_number : Int
ar_uuid : @rpc.Uuid
api : Int
slot_number : Int
subslot_number : Int
index : Int
record_data_length : Int
} derive(Eq, Debug)
///|
/// Encode IOD Read Request Header (block body, 58 bytes).
pub fn encode_iod_read_req_header(req : IODReadReqHeader) -> Bytes {
let output : Array[Byte] = []
push_u16_be(output, req.seq_number)
append_bytes(output, req.ar_uuid.to_dce_bytes_le())
push_u32_be(output, req.api)
push_u16_be(output, req.slot_number)
push_u16_be(output, req.subslot_number)
// 2 bytes padding
push_u16_be(output, 0)
push_u16_be(output, req.index)
push_u32_be(output, req.record_data_length)
// target_ar_uuid + reserved padding (24 bytes in the Read.req layout)
for i = 0; i < 16; i = i + 1 {
output.push(b'\x00')
}
for i = 0; i < 8; i = i + 1 {
output.push(b'\x00')
}
Bytes::from_array(output)
}
///|
/// IOD Read Response Header.
pub(all) struct IODReadResHeader {
seq_number : Int
ar_uuid : @rpc.Uuid
api : Int
slot_number : Int
subslot_number : Int
index : Int
record_data_length : Int
additional_value1 : Int
additional_value2 : Int
} derive(Eq, Debug)
///|
/// Parse IOD Read Response Header from body bytes.
pub fn parse_iod_read_res_header(
data : Bytes,
offset : Int,
) -> IODReadResHeader raise @frame.FrameError {
guard data.length() >= offset + 38 else {
raise @frame.FrameError::InvalidMacLength(data.length())
}
IODReadResHeader::{
seq_number: read_u16_be(data, offset),
ar_uuid: @rpc.Uuid::from_dce_bytes_le(data, offset + 2),
api: read_u32_be(data, offset + 18),
slot_number: read_u16_be(data, offset + 22),
subslot_number: read_u16_be(data, offset + 24),
index: read_u16_be(data, offset + 28),
record_data_length: read_u32_be(data, offset + 30),
additional_value1: read_u16_be(data, offset + 34),
additional_value2: read_u16_be(data, offset + 36),
}
}
///|
/// IOD Write Request Header.
pub(all) struct IODWriteReqHeader {
seq_number : Int
ar_uuid : @rpc.Uuid
api : Int
slot_number : Int
subslot_number : Int
index : Int
record_data_length : Int
} derive(Eq, Debug)
///|
/// Encode IOD Write Request Header (block body, 38 bytes).
pub fn encode_iod_write_req_header(req : IODWriteReqHeader) -> Bytes {
let output : Array[Byte] = []
push_u16_be(output, req.seq_number)
append_bytes(output, req.ar_uuid.to_dce_bytes_le())
push_u32_be(output, req.api)
push_u16_be(output, req.slot_number)
push_u16_be(output, req.subslot_number)
// 2 bytes padding
push_u16_be(output, 0)
push_u16_be(output, req.index)
push_u32_be(output, req.record_data_length)
// target_ar_uuid padding (16 bytes zeros)
for i = 0; i < 16; i = i + 1 {
output.push(b'\x00')
}
Bytes::from_array(output)
}
///|
/// Encode IOD Write Request Header plus RecordDataWrite bytes.
///
/// This mirrors the C# `ak` block used by `DceClient.Write`: the fixed header
/// is 58 bytes, followed by the user-specified record data. The surrounding IO
/// block length field must still exclude the user data bytes.
pub fn encode_iod_write_req_with_data(
req : IODWriteReqHeader,
record_data : Bytes,
) -> Bytes {
let output : Array[Byte] = []
push_u16_be(output, req.seq_number)
append_bytes(output, req.ar_uuid.to_dce_bytes_le())
push_u32_be(output, req.api)
push_u16_be(output, req.slot_number)
push_u16_be(output, req.subslot_number)
// 2 bytes padding
push_u16_be(output, 0)
push_u16_be(output, req.index)
push_u32_be(output, record_data.length())
// target_ar_uuid + reserved padding (24 bytes in the Write.req layout)
for i = 0; i < 24; i = i + 1 {
output.push(b'\x00')
}
append_bytes(output, record_data)
Bytes::from_array(output)
}
///|
/// IOD Control Request — used for PrmEnd, ApplicationReady, Release.
pub(all) struct IODControlReq {
ar_uuid : @rpc.Uuid
session_key : Int
control_command : Int
control_block_properties : Int
} derive(Eq, Debug)
///|
/// Encode IOD Control Request body.
pub fn encode_iod_control_req(req : IODControlReq) -> Bytes {
let output : Array[Byte] = []
// 2 bytes padding
push_u16_be(output, 0)
append_bytes(output, req.ar_uuid.to_dce_bytes_le())
push_u16_be(output, req.session_key)
// 2 bytes padding
push_u16_be(output, 0)
push_u16_be(output, req.control_command)
push_u16_be(output, req.control_block_properties)
Bytes::from_array(output)
}
///|
/// Parse IOD Control Request from body bytes.
pub fn parse_iod_control_req(
data : Bytes,
offset : Int,
) -> IODControlReq raise @frame.FrameError {
guard data.length() >= offset + 26 else {
raise @frame.FrameError::InvalidMacLength(data.length())
}
IODControlReq::{
ar_uuid: @rpc.Uuid::from_dce_bytes_le(data, offset + 2),
session_key: read_u16_be(data, offset + 18),
control_command: read_u16_be(data, offset + 22),
control_block_properties: read_u16_be(data, offset + 24),
}
}
///|
/// Release Block Request.
pub(all) struct ReleaseBlockReq {
ar_uuid : @rpc.Uuid
session_key : Int
control_command : Int
control_block_properties : Int
} derive(Eq, Debug)
///|
/// Encode Release Block Request body (same layout as IOD Control).
pub fn encode_release_block_req(req : ReleaseBlockReq) -> Bytes {
encode_iod_control_req(IODControlReq::{
ar_uuid: req.ar_uuid,
session_key: req.session_key,
control_command: req.control_command,
control_block_properties: req.control_block_properties,
})
}
///|
/// Format IOD Read Request summary.
pub fn format_iod_read_req(req : IODReadReqHeader) -> String {
let lines : Array[String] = []
lines.push("seq=" + req.seq_number.to_string())
lines.push("ar_uuid=" + req.ar_uuid.to_hex())
lines.push("api=" + req.api.to_string())
lines.push("slot=" + req.slot_number.to_string())
lines.push("subslot=" + req.subslot_number.to_string())
lines.push("index=0x" + @frame.uint16_to_hex(req.index))
lines.push("record_data_length=" + req.record_data_length.to_string())
lines.join("\n")
}
///|
/// Format IOD Control summary.
pub fn format_iod_control(req : IODControlReq) -> String {
let lines : Array[String] = []
lines.push("ar_uuid=" + req.ar_uuid.to_hex())
lines.push("session_key=" + req.session_key.to_string())
lines.push("control_command=" + control_command_label(req.control_command))
lines.join("\n")
}