///|
/// AR lifecycle states (PN-AL-Services ยง4.7).
pub(all) enum ArState {
Closed
Init
Open
Active
} derive(Eq, Debug)
///|
/// AR (Application Relationship) block request.
pub(all) struct ARBlockReq {
ar_type : Int
ar_uuid : @rpc.Uuid
session_key : Int
cm_initiator_mac : @frame.MacAddress
cm_initiator_object_uuid : @rpc.Uuid
ar_properties : Int
cm_initiator_activity_timeout_factor : Int
cm_initiator_udp_rt_port : Int
cm_initiator_station_name : String
} derive(Eq)
///|
fn clrpc_cm_initiator_object_uuid() -> @rpc.Uuid {
@rpc.Uuid::{
bytes: Bytes::from_array([
b'\xDE', b'\xA0', b'\x00', b'\x00', b'\x6C', b'\x97', b'\x11', b'\xD1', b'\x82',
b'\x71', b'\x00', b'\xA0', b'\x24', b'\x42', b'\xDF', b'\x7D',
]),
}
}
///|
pub fn ARBlockReq::default(
ar_uuid : @rpc.Uuid,
cm_mac : @frame.MacAddress,
station_name : String,
) -> ARBlockReq {
ARBlockReq::{
ar_type: ar_type_io_controller,
ar_uuid,
session_key: 0,
cm_initiator_mac: cm_mac,
cm_initiator_object_uuid: clrpc_cm_initiator_object_uuid(),
ar_properties: 0x00000011,
cm_initiator_activity_timeout_factor: 600,
cm_initiator_udp_rt_port: 0x8892,
cm_initiator_station_name: station_name,
}
}
///|
/// Encode AR block request body (without block header).
pub fn encode_ar_block_req(req : ARBlockReq) -> Bytes {
let output : Array[Byte] = []
push_u16_be(output, req.ar_type)
append_bytes(output, req.ar_uuid.to_dce_bytes_le())
push_u16_be(output, req.session_key)
append_bytes(output, req.cm_initiator_mac.octets())
append_bytes(output, req.cm_initiator_object_uuid.to_bytes())
push_u32_be(output, req.ar_properties)
push_u16_be(output, req.cm_initiator_activity_timeout_factor)
push_u16_be(output, req.cm_initiator_udp_rt_port)
let name_bytes = req.cm_initiator_station_name
.to_array()
.map(fn(c) { c.to_int().to_byte() })
push_u16_be(output, name_bytes.length())
for b in name_bytes {
output.push(b)
}
if name_bytes.length() % 2 == 1 {
output.push(b'\x00')
}
Bytes::from_array(output)
}
///|
/// AR block response.
pub(all) struct ARBlockRes {
ar_type : Int
ar_uuid : @rpc.Uuid
session_key : Int
cm_responder_mac : @frame.MacAddress
cm_responder_udp_rt_port : Int
} derive(Eq)
///|
/// Parse AR block response from body bytes.
pub fn parse_ar_block_res(
data : Bytes,
offset : Int,
) -> ARBlockRes raise @frame.FrameError {
guard data.length() >= offset + 28 else {
raise @frame.FrameError::InvalidMacLength(data.length())
}
let mac_bytes : Array[Byte] = []
for i = 0; i < 6; i = i + 1 {
mac_bytes.push(data[offset + 20 + i])
}
ARBlockRes::{
ar_type: read_u16_be(data, offset),
ar_uuid: @rpc.Uuid::from_dce_bytes_le(data, offset + 2),
session_key: read_u16_be(data, offset + 18),
cm_responder_mac: @frame.MacAddress::new(Bytes::from_array(mac_bytes)),
cm_responder_udp_rt_port: read_u16_be(data, offset + 26),
}
}
///|
/// Format AR block request summary.
pub fn format_ar_block_req(req : ARBlockReq) -> String {
let lines : Array[String] = []
lines.push("ar_type=" + req.ar_type.to_string())
lines.push("ar_uuid=" + req.ar_uuid.to_hex())
lines.push("session_key=" + req.session_key.to_string())
lines.push("cm_mac=" + req.cm_initiator_mac.to_hex())
lines.push("station_name=" + req.cm_initiator_station_name)
lines.push("ar_properties=0x" + @frame.uint32_to_hex(req.ar_properties))
lines.join("\n")
}