///|
/// Standard PROFINET RPC UDP port.
pub let rpc_udp_port : Int = 34964
///|
/// PROFINET multicast MAC for DCE/RPC.
pub let rpc_multicast_mac : String = "01:0E:CF:00:00:00"
///|
/// DCE/RPC packet types.
pub let packet_type_request : Byte = 0
///|
pub let packet_type_ping : Byte = 1
///|
pub let packet_type_response : Byte = 2
///|
pub let packet_type_no_call : Byte = 5
///|
pub let packet_type_reject : Byte = 6
///|
pub fn packet_type_label(pt : Byte) -> String {
match pt {
b'\x00' => "Request"
b'\x01' => "Ping"
b'\x02' => "Response"
b'\x05' => "NoCall"
b'\x06' => "Reject"
_ => "Unknown(" + pt.to_int().to_string() + ")"
}
}
///|
/// Well-known PROFINET IO CM activity UUIDs (as hex strings).
/// PNIO Device UUID for endpoint mapper.
pub let uuid_pnio_device : String = "DEA00001-6C97-11D1-8271-00A02442DF7D"
///|
/// PNIO Controller UUID.
pub let uuid_pnio_controller : String = "DEA00002-6C97-11D1-8271-00A02442DF7D"
///|
/// PNIO Supervisor UUID.
pub let uuid_pnio_supervisor : String = "DEA00003-6C97-11D1-8271-00A02442DF7D"
///|
/// PNIO Parameterization UUID.
pub let uuid_pnio_parameterization : String = "DEA00004-6C97-11D1-8271-00A02442DF7D"
///|
/// Endpoint Mapper UUID (DCE standard).
pub let uuid_endpoint_mapper : String = "E1AF8308-5D1F-11C9-91A4-08002B14A0FA"
///|
/// UUID data type — 16-byte identifier.
pub(all) struct Uuid {
bytes : Bytes
} derive(Eq, Debug)
///|
pub fn Uuid::empty() -> Uuid {
Uuid::{ bytes: Bytes::make(16, b'\x00') }
}
///|
pub fn Uuid::from_bytes(
data : Bytes,
offset : Int,
) -> Uuid raise @frame.FrameError {
guard data.length() >= offset + 16 else {
raise @frame.FrameError::InvalidMacLength(data.length())
}
let bytes : Array[Byte] = []
for i = 0; i < 16; i = i + 1 {
bytes.push(data[offset + i])
}
Uuid::{ bytes: Bytes::from_array(bytes) }
}
///|
fn swap_dce_uuid_fields(src : Bytes) -> Bytes {
Bytes::from_array([
src[3],
src[2],
src[1],
src[0],
src[5],
src[4],
src[7],
src[6],
src[8],
src[9],
src[10],
src[11],
src[12],
src[13],
src[14],
src[15],
])
}
///|
/// Parse a DCE/RPC little-endian wire UUID into canonical UUID byte order.
pub fn Uuid::from_dce_bytes_le(
data : Bytes,
offset : Int,
) -> Uuid raise @frame.FrameError {
guard data.length() >= offset + 16 else {
raise @frame.FrameError::InvalidMacLength(data.length())
}
Uuid::{ bytes: swap_dce_uuid_fields(data[offset:offset + 16].to_owned()) }
}
///|
fn hex_digit_value(c : Char) -> Int raise @frame.FrameError {
match c {
'0'..='9' => c.to_int() - '0'.to_int()
'a'..='f' => c.to_int() - 'a'.to_int() + 10
'A'..='F' => c.to_int() - 'A'.to_int() + 10
_ => raise @frame.FrameError::InvalidHexText(c.to_string())
}
}
///|
/// Parse a UUID from its canonical hex string (e.g.
/// "DEA00001-6C97-11D1-8271-00A02442DF7D"). Bytes are taken in written
/// (big-endian field) order; dashes are ignored.
pub fn Uuid::from_hex(text : String) -> Uuid raise @frame.FrameError {
let nibbles : Array[Int] = []
for c in text {
if c != '-' {
nibbles.push(hex_digit_value(c))
}
}
guard nibbles.length() == 32 else {
raise @frame.FrameError::InvalidHexText(text)
}
let bytes : Array[Byte] = []
for i = 0; i < 16; i = i + 1 {
bytes.push((((nibbles[i * 2] << 4) | nibbles[i * 2 + 1]) & 0xFF).to_byte())
}
Uuid::{ bytes: Bytes::from_array(bytes) }
}
///|
pub fn Uuid::to_hex(self : Uuid) -> String {
let b = self.bytes
let hex = fn(idx : Int) -> String {
@frame.uint16_to_hex((b[idx].to_int() << 8) + b[idx + 1].to_int())
}
let h0 = @frame.uint32_to_hex(
(b[0].to_int() << 24) +
(b[1].to_int() << 16) +
(b[2].to_int() << 8) +
b[3].to_int(),
)
h0 +
"-" +
hex(4) +
"-" +
hex(6) +
"-" +
hex(8) +
"-" +
hex(10) +
hex(12) +
hex(14)
}
///|
pub fn Uuid::to_bytes(self : Uuid) -> Bytes {
self.bytes
}
///|
/// Return the DCE/RPC little-endian wire representation used when DREP=0x10.
pub fn Uuid::to_dce_bytes_le(self : Uuid) -> Bytes {
swap_dce_uuid_fields(self.bytes)
}
///|
fn push_u16_le(output : Array[Byte], value : Int) -> Unit {
output.push((value & 0xFF).to_byte())
output.push(((value >> 8) & 0xFF).to_byte())
}
///|
fn push_u32_le(output : Array[Byte], value : Int) -> Unit {
output.push((value & 0xFF).to_byte())
output.push(((value >> 8) & 0xFF).to_byte())
output.push(((value >> 16) & 0xFF).to_byte())
output.push(((value >> 24) & 0xFF).to_byte())
}
///|
fn read_u16_le(data : Bytes, offset : Int) -> Int {
data[offset].to_int() + (data[offset + 1].to_int() << 8)
}
///|
fn read_u32_le(data : Bytes, offset : Int) -> Int {
data[offset].to_int() +
(data[offset + 1].to_int() << 8) +
(data[offset + 2].to_int() << 16) +
(data[offset + 3].to_int() << 24)
}
///|
fn append_bytes(output : Array[Byte], data : Bytes) -> Unit {
for byte in data {
output.push(byte)
}
}