ddp_rs/protocol/
id.rs

1use serde::{Deserialize, Serialize};
2
3/// Protocol ID used to identify the purpose of a packet.
4///
5/// IDs are used to differentiate between pixel data, control messages, configuration
6/// queries, and other packet types. The ID space is divided into several ranges:
7///
8/// - 0: Reserved
9/// - 1: Default (standard pixel data)
10/// - 2-245, 247-249: Custom IDs for application-specific use
11/// - 246: Control messages (JSON control read/write)
12/// - 250: Configuration messages (JSON config read/write)
13/// - 251: Status messages (JSON status read-only)
14/// - 254: DMX data
15/// - 255: Broadcast to all displays
16///
17/// # Examples
18///
19/// ```
20/// use ddp_rs::protocol::ID;
21///
22/// // Standard pixel data
23/// let pixel_id = ID::Default;
24///
25/// // Control message
26/// let control_id = ID::Control;
27///
28/// // Custom application ID
29/// let custom_id = ID::Custom(42);
30/// ```
31#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Hash, Clone, Copy, Default)]
32pub enum ID {
33    /// Reserved, should not be used
34    Reserved,
35
36    /// Default ID for standard pixel data
37    #[default]
38    Default,
39
40    /// Custom ID in ranges 2-245 and 247-249
41    Custom(u8),
42
43    /// Control message ID (246) for JSON control read/write
44    Control,
45
46    /// Configuration message ID (250) for JSON config read/write
47    Config,
48
49    /// Status message ID (251) for JSON status read-only
50    Status,
51
52    /// DMX data ID (254)
53    DMX,
54
55    /// Broadcast to all displays (255)
56    Broadcast,
57}
58
59impl From<u8> for ID {
60    fn from(value: u8) -> Self {
61        match value {
62            0 => ID::Reserved,
63            1 => ID::Default,
64            246 => ID::Control,
65            250 => ID::Config,
66            251 => ID::Status,
67            254 => ID::DMX,
68            255 => ID::Broadcast,
69            // All other values are custom IDs (2-245, 247-249, 252-253)
70            _ => ID::Custom(value),
71        }
72    }
73}
74
75impl Into<u8> for ID {
76    fn into(self) -> u8 {
77        match self {
78            ID::Reserved => 0,
79            ID::Default => 1,
80            ID::Control => 246,
81            ID::Config => 250,
82            ID::Status => 251,
83            ID::DMX => 254,
84            ID::Broadcast => 255,
85            ID::Custom(value) => {
86                // Valid custom ranges: 2-245, 247-249, 252-253
87                if matches!(value, 2..=245 | 247..=249 | 252..=253) {
88                    value
89                } else {
90                    1 // Default to ID 1 if invalid
91                }
92            }
93        }
94    }
95}
96
97#[cfg(test)]
98mod tests {
99    use super::*;
100
101    #[test]
102    fn test_id_parse() {
103        // Custom
104        let id = ID::from(212);
105        assert_eq!(id, ID::Custom(212));
106
107        // Default
108        let id = ID::from(1);
109        assert_eq!(id, ID::Default);
110
111        // Status
112        let id = ID::from(251);
113        assert_eq!(id, ID::Status);
114
115        // Reserved
116        let id = ID::from(0);
117        assert_eq!(id, ID::Reserved);
118    }
119}