tiny_artnet/
poll_reply.rs

1use bytes::BufMut;
2
3use crate::put_esta_manufacturer_code;
4
5const OP_POLL_REPLY: u16 = 0x2100;
6
7#[derive(Debug)]
8pub struct PollReply<'a> {
9    pub ip_address: &'a [u8; 4],
10    pub port: u16,
11    pub firmware_version: u16,
12    // Note: I am less sure about how the following fields work in practice. If there are ergonomic improvements to be had I am open to Pull Requests:
13    /// Bits 14-8 of the 15 bit Port-Address are encoded into the bottom 7 bits of this field.
14    pub net_switch: u8,
15    /// Bits 7-4 of the 15 bit Port-Address are encoded into the bottom 4 bits of this field.
16    pub sub_switch: u8,
17    /// The Oem word describes the equipment vendor and the feature set available. Bit 15 high indicates extended features available.
18    pub oem: u16,
19    /// The firmware version of the User Bios Extension Area (UBEA) If the UBEA is not programmed, this field contains zero.
20    pub ubea_version: u8,
21    /// General Status register containing bit fields as follows:
22    /// 7-6 Indicator state.
23    ///     00 Indicator state unknown.
24    ///     01 Indicators in Locate / Identify Mode.
25    ///     10 Indicators in Mute Mode.
26    ///     11 Indicators in Normal Mode.
27    /// 5-4 Port-Address Programming Authority
28    ///     00 Port-Address Programming Authority unknown.
29    ///     01 All Port-Address set by front panel controls.
30    ///     10 All or part of Port-Address programmed by network or Web browser.
31    ///     11 Not used.
32    /// 3 Not implemented, transmit as zero, receivers do not test.
33    /// 2
34    ///     0 = Normal firmware boot (from flash). Nodes that do not support dual boot, clear this field to zero.
35    ///     1 = Booted from ROM.
36    /// 1
37    ///     0 = Not capable of Remote Device Management (RDM).
38    ///     1 = Capable of Remote Device Management (RDM).
39    /// 0
40    ///     0 = UBEA not present or corrupt
41    ///     1 = UBEA present
42    pub status1: u8,
43    pub esta_manufacturer_code: crate::ESTAManufacturerCode,
44    /// Note: The spec specifies ASCII characters only
45    pub short_name: &'a str,
46    /// Note: The spec specifies ASCII characters only
47    pub long_name: &'a str,
48    /// Note: The spec specifies ASCII characters only
49    pub node_report: &'a str,
50    pub num_ports: u16,
51    pub port_types: &'a [u8; 4],
52    pub good_input: &'a [u8; 4],
53    pub good_output_a: &'a [u8; 4],
54    pub swin: &'a [u8; 4],
55    pub swout: &'a [u8; 4],
56    pub acn_priority: u8,
57    pub sw_macro: u8,
58    pub sw_remote: u8,
59    pub style: u8,
60    pub mac_address: &'a [u8; 6],
61    pub bind_ip_address: &'a [u8; 4],
62    pub bind_index: u8,
63    pub status2: u8,
64    pub good_output_b: &'a [u8; 4],
65    pub status3: u8,
66    /// RDMnet & LLRP Default Responder UID
67    pub default_responder_uid: &'a [u8; 6],
68}
69
70impl<'a> Default for PollReply<'a> {
71    fn default() -> Self {
72        Self {
73            ip_address: crate::DEFAULT_4_BYTES,
74            port: Default::default(),
75            firmware_version: Default::default(),
76            net_switch: Default::default(),
77            sub_switch: Default::default(),
78            oem: Default::default(),
79            ubea_version: Default::default(),
80            status1: 0b1100_0000, // Indicator Mode: Normal
81            esta_manufacturer_code: Default::default(),
82            short_name: Default::default(),
83            long_name: Default::default(),
84            node_report: Default::default(),
85            num_ports: Default::default(),
86            port_types: crate::DEFAULT_4_BYTES,
87            good_input: crate::DEFAULT_4_BYTES,
88            good_output_a: crate::DEFAULT_4_BYTES,
89            swin: crate::DEFAULT_4_BYTES,
90            swout: crate::DEFAULT_4_BYTES,
91            acn_priority: Default::default(),
92            sw_macro: Default::default(),
93            sw_remote: Default::default(),
94            style: Default::default(),
95            mac_address: crate::DEFAULT_6_BYTES,
96            bind_ip_address: crate::DEFAULT_4_BYTES,
97            bind_index: Default::default(),
98            status2: Default::default(),
99            good_output_b: crate::DEFAULT_4_BYTES,
100            status3: Default::default(),
101            default_responder_uid: crate::DEFAULT_6_BYTES,
102        }
103    }
104}
105
106impl<'a> PollReply<'a> {
107    /// Serializes the PollReply into the provided buffer.
108    ///
109    /// Note: short name, long name and report will be truncated to 18, 64, and 64 bytes respectively
110    pub fn serialize(&self, mut buf: &mut [u8]) -> usize {
111        let initial_buf_len = buf.len();
112
113        buf.put_slice(crate::ID);
114        buf.put_u16_le(OP_POLL_REPLY);
115        buf.put_slice(self.ip_address);
116        buf.put_u16_le(self.port);
117        buf.put_u16(self.firmware_version);
118        buf.put_u8(self.net_switch);
119        buf.put_u8(self.sub_switch);
120        buf.put_u16(self.oem);
121        buf.put_u8(self.ubea_version);
122        buf.put_u8(self.status1);
123        put_esta_manufacturer_code(&mut buf, &self.esta_manufacturer_code);
124
125        crate::put_padded_str::<18, _>(&mut buf, &self.short_name);
126        crate::put_padded_str::<64, _>(&mut buf, &self.long_name);
127        crate::put_padded_str::<64, _>(&mut buf, &self.node_report);
128
129        buf.put_u16(self.num_ports);
130        buf.put_slice(self.port_types);
131        buf.put_slice(self.good_input);
132        buf.put_slice(self.good_output_a);
133        buf.put_slice(self.swin);
134        buf.put_slice(self.swout);
135        buf.put_u8(self.acn_priority);
136        buf.put_u8(self.sw_macro);
137        buf.put_u8(self.sw_remote);
138        // Spare
139        buf.put_slice(&[0u8; 3]);
140        buf.put_u8(self.style);
141        buf.put_slice(self.mac_address);
142        buf.put_slice(self.bind_ip_address);
143        buf.put_u8(self.bind_index);
144        buf.put_u8(self.status2);
145        buf.put_slice(self.good_output_b);
146        buf.put_u8(self.status3);
147        buf.put_slice(self.default_responder_uid);
148        // Filler
149        buf.put_slice(&[0u8; 15]);
150
151        return initial_buf_len - buf.len();
152    }
153}
154
155// TODO: Poll Reply Parser
156// pub fn from_str<'a>(s: &'a [u8]) -> Result<PollReply<'a>, crate::Error<'a>> {
157// }