vita49/
command.rs

1// SPDX-FileCopyrightText: 2025 The vita49-rs Authors
2//
3// SPDX-License-Identifier: MIT OR Apache-2.0
4/*!
5Data structures and methods related to command payloads
6(ANSI/VITA-49.2-2017 section 8).
7*/
8
9use core::fmt;
10
11use crate::{
12    prelude::*, Ack, Cancellation, CommandPayload, Control, ControlAckMode, IdFormat, QueryAck,
13};
14use deku::prelude::*;
15
16/// Main command payload structure.
17#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, DekuRead, DekuWrite)]
18#[deku(
19    endian = "endian",
20    ctx = "endian: deku::ctx::Endian, packet_header: &PacketHeader"
21)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
23pub struct Command {
24    /// Control acknowledgement mode.
25    cam: ControlAckMode,
26    /// Message ID.
27    message_id: u32,
28    /// Controllee ID.
29    #[deku(cond = "cam.controllee_enabled() && cam.controllee_id_format() == IdFormat::Id32bit")]
30    controllee_id: Option<u32>,
31    /// Controllee UUID.
32    #[deku(
33        cond = "cam.controllee_enabled() && cam.controllee_id_format() == IdFormat::Uuid128bit"
34    )]
35    controllee_uuid: Option<u128>,
36    /// Controller ID.
37    #[deku(cond = "cam.controller_enabled() && cam.controller_id_format() == IdFormat::Id32bit")]
38    controller_id: Option<u32>,
39    /// Controller UUID.
40    #[deku(
41        cond = "cam.controller_enabled() && cam.controller_id_format() == IdFormat::Uuid128bit"
42    )]
43    controller_uuid: Option<u128>,
44    #[deku(ctx = "&cam, packet_header")]
45    command_payload: CommandPayload,
46}
47
48impl Default for Command {
49    fn default() -> Self {
50        Self {
51            cam: Default::default(),
52            message_id: Default::default(),
53            controllee_id: Default::default(),
54            controllee_uuid: Default::default(),
55            controller_id: Default::default(),
56            controller_uuid: Default::default(),
57            command_payload: CommandPayload::Control(Control::default()),
58        }
59    }
60}
61
62impl Command {
63    /// Create a new, empty control packet.
64    pub fn new_control() -> Command {
65        Command::default()
66    }
67
68    /// Create a new, empty cancellation packet.
69    pub fn new_cancellation() -> Command {
70        Self {
71            cam: Default::default(),
72            message_id: Default::default(),
73            controllee_id: Default::default(),
74            controllee_uuid: Default::default(),
75            controller_id: Default::default(),
76            controller_uuid: Default::default(),
77            command_payload: CommandPayload::Cancellation(Cancellation::default()),
78        }
79    }
80
81    /// Create a new, empty validation ACK packet.
82    pub fn new_validation_ack() -> Command {
83        let mut cam = ControlAckMode::default();
84        cam.set_validation();
85        Self {
86            cam,
87            message_id: Default::default(),
88            controllee_id: Default::default(),
89            controllee_uuid: Default::default(),
90            controller_id: Default::default(),
91            controller_uuid: Default::default(),
92            command_payload: CommandPayload::ValidationAck(Ack::default()),
93        }
94    }
95
96    /// Create a new, empty execution ACK packet.
97    pub fn new_exec_ack() -> Command {
98        let mut cam = ControlAckMode::default();
99        cam.set_execution();
100        Self {
101            cam,
102            message_id: Default::default(),
103            controllee_id: Default::default(),
104            controllee_uuid: Default::default(),
105            controller_id: Default::default(),
106            controller_uuid: Default::default(),
107            command_payload: CommandPayload::ExecAck(Ack::default()),
108        }
109    }
110
111    /// Create a new, empty query ACK packet.
112    pub fn new_query_ack() -> Command {
113        let mut cam = ControlAckMode::default();
114        cam.set_state();
115        Self {
116            cam,
117            message_id: Default::default(),
118            controllee_id: Default::default(),
119            controllee_uuid: Default::default(),
120            controller_id: Default::default(),
121            controller_uuid: Default::default(),
122            command_payload: CommandPayload::QueryAck(QueryAck::default()),
123        }
124    }
125
126    /// Get the packet message ID.
127    pub fn message_id(&self) -> u32 {
128        self.message_id
129    }
130
131    /// Set the packet message ID.
132    pub fn set_message_id(&mut self, message_id: u32) {
133        self.message_id = message_id;
134    }
135
136    /// Get the packet's Control Ack Mode (CAM)
137    pub fn cam(&self) -> ControlAckMode {
138        self.cam
139    }
140
141    /// Set the packet's Control Ack Mode (CAM)
142    /// # Example
143    /// ```
144    /// use vita49::{prelude::*, ControlAckMode, ActionMode};
145    /// let mut packet = Vrt::new_control_packet();
146    /// let command_mut = packet.payload_mut().command_mut().unwrap();
147    /// let mut cam = ControlAckMode::default();
148    /// cam.set_action_mode(ActionMode::Execute);
149    /// command_mut.set_cam(cam);
150    /// assert_eq!(command_mut.cam().action_mode(), ActionMode::Execute);
151    /// ````
152    pub fn set_cam(&mut self, mode: ControlAckMode) {
153        self.cam = mode;
154    }
155
156    /// Get the controllee identifier.
157    pub fn controllee_id(&self) -> Option<u32> {
158        self.controllee_id
159    }
160    /// Sets the controllee identifier. If `None` is passed, the field
161    /// will be unset.
162    ///
163    /// # Errors
164    /// If this function is called while the `controllee_uuid` field is set,
165    /// an error will be returned as these fields are mutually exclusive.
166    pub fn set_controllee_id(&mut self, id: Option<u32>) -> Result<(), VitaError> {
167        if id.is_some() && self.controllee_uuid.is_some() {
168            return Err(VitaError::TriedIdWhenUuidSet);
169        }
170        self.controllee_id = id;
171        if id.is_some() {
172            self.cam.enable_controllee();
173            self.cam.set_controllee_id_format(IdFormat::Id32bit);
174        } else if self.controllee_uuid.is_none() {
175            self.cam.disable_controllee();
176        }
177        Ok(())
178    }
179
180    /// Get the controller identifier.
181    pub fn controller_id(&self) -> Option<u32> {
182        self.controller_id
183    }
184    /// Sets the controller identifier. If `None` is passed, the field
185    /// will be unset.
186    ///
187    /// # Errors
188    /// If this function is called while the `controller_uuid` field is set,
189    /// an error will be returned as these fields are mutually exclusive.
190    pub fn set_controller_id(&mut self, id: Option<u32>) -> Result<(), VitaError> {
191        if id.is_some() && self.controller_uuid.is_some() {
192            return Err(VitaError::TriedIdWhenUuidSet);
193        }
194        self.controller_id = id;
195        if id.is_some() {
196            self.cam.enable_controller();
197            self.cam.set_controller_id_format(IdFormat::Id32bit);
198        } else if self.controller_uuid.is_none() {
199            self.cam.disable_controller();
200        }
201        Ok(())
202    }
203
204    /// Get the controllee UUID.
205    pub fn controllee_uuid(&self) -> Option<u128> {
206        self.controllee_uuid
207    }
208    /// Sets the controllee UUID. If `None` is passed, the field
209    /// will be unset.
210    ///
211    /// # Errors
212    /// If this function is called while the `controllee_id` field is set,
213    /// an error will be returned as these fields are mutually exclusive.
214    pub fn set_controllee_uuid(&mut self, uuid: Option<u128>) -> Result<(), VitaError> {
215        if uuid.is_some() && self.controllee_id.is_some() {
216            return Err(VitaError::TriedUuidWhenIdSet);
217        }
218        self.controllee_uuid = uuid;
219        if uuid.is_some() {
220            self.cam.enable_controllee();
221            self.cam.set_controllee_id_format(IdFormat::Uuid128bit);
222        } else if self.controllee_id.is_none() {
223            self.cam.disable_controllee();
224        }
225        Ok(())
226    }
227
228    /// Get the controller UUID.
229    pub fn controller_uuid(&self) -> Option<u128> {
230        self.controller_uuid
231    }
232    /// Sets the controller UUID. If `None` is passed, the field
233    /// will be unset.
234    ///
235    /// # Errors
236    /// If this function is called while the `controller_id` field is set,
237    /// an error will be returned as these fields are mutually exclusive.
238    pub fn set_controller_uuid(&mut self, uuid: Option<u128>) -> Result<(), VitaError> {
239        if uuid.is_some() && self.controller_id.is_some() {
240            return Err(VitaError::TriedUuidWhenIdSet);
241        }
242        self.controller_uuid = uuid;
243        if uuid.is_some() {
244            self.cam.enable_controller();
245            self.cam.set_controller_id_format(IdFormat::Uuid128bit);
246        } else if self.controller_id.is_none() {
247            self.cam.disable_controller();
248        }
249        Ok(())
250    }
251
252    /// Get a reference to the underlying command payload enumeration.
253    pub fn payload(&self) -> &CommandPayload {
254        &self.command_payload
255    }
256
257    /// Get a mutable reference to the underlying command payload enumeration.
258    pub fn payload_mut(&mut self) -> &mut CommandPayload {
259        &mut self.command_payload
260    }
261
262    /// Get the size of the command packet (in 32-bit words).
263    pub fn size_words(&self) -> u16 {
264        let mut ret = self.cam.size_words();
265        ret += 1; // message_id
266        if self.controllee_id.is_some() {
267            ret += 1;
268        } else if self.controllee_uuid.is_some() {
269            ret += 4;
270        }
271        if self.controller_id.is_some() {
272            ret += 1;
273        } else if self.controller_uuid.is_some() {
274            ret += 4;
275        }
276        ret += self.command_payload.size_words();
277        ret
278    }
279}
280
281impl TryFrom<Payload> for Command {
282    type Error = Payload;
283
284    fn try_from(value: Payload) -> Result<Self, Self::Error> {
285        match value {
286            Payload::Command(c) => Ok(c),
287            a => Err(a),
288        }
289    }
290}
291
292impl fmt::Display for Command {
293    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
294        write!(f, "{}", self.cam)?;
295        writeln!(f, "Message ID: {:x}", self.message_id)?;
296        if let Some(cid) = self.controllee_id {
297            writeln!(f, "Controllee ID: {cid:x}")?;
298        }
299        if let Some(cuuid) = self.controllee_uuid {
300            writeln!(f, "Controllee UUID: {cuuid:x}")?;
301        }
302        if let Some(cid) = self.controller_id {
303            writeln!(f, "Controller ID: {cid:x}")?;
304        }
305        if let Some(cuuid) = self.controller_uuid {
306            writeln!(f, "Controller UUID: {cuuid:x}")?;
307        }
308        match &self.command_payload {
309            CommandPayload::Control(p) => write!(f, "{p}")?,
310            CommandPayload::Cancellation(p) => write!(f, "{p}")?,
311            CommandPayload::ValidationAck(p) => write!(f, "Validation {p}")?,
312            CommandPayload::ExecAck(p) => write!(f, "Execution {p}")?,
313            CommandPayload::QueryAck(p) => write!(f, "{p}")?,
314        };
315        Ok(())
316    }
317}
318
319#[cfg(test)]
320mod tests {
321    use crate::prelude::*;
322    use crate::{ActionMode, ControlAckMode, IdFormat, Tsf, Tsi};
323
324    #[test]
325    fn create_control_packet() {
326        let mut packet = Vrt::new_control_packet();
327        packet.set_stream_id(Some(0xDEADBEEF));
328        packet.set_integer_timestamp(Some(0), Tsi::Utc).unwrap();
329        packet
330            .set_fractional_timestamp(Some(0), Tsf::SampleCount)
331            .unwrap();
332        let command = packet.payload_mut().command_mut().unwrap();
333        command.set_message_id(123);
334        let mut cam = ControlAckMode::default();
335        cam.enable_controllee();
336        cam.enable_controller();
337        cam.set_controllee_id_format(IdFormat::Id32bit);
338        cam.set_controller_id_format(IdFormat::Uuid128bit);
339        cam.set_action_mode(ActionMode::Execute);
340        cam.set_partial_packet_impl_permitted();
341        cam.set_warnings_permitted();
342        cam.set_validation();
343        cam.set_warning();
344        cam.set_error();
345        command.set_cam(cam);
346        command.controllee_id = Some(123);
347        command.controller_uuid = Some(321);
348    }
349}