1use core::fmt;
2
3use crate::*;
4use crate::util::hex_char;
5
6pub type Result<T> = core::result::Result<T, SigNetError>;
7
8pub type SoemCode = u32;
9
10pub fn soem_code(mfg_id: u16, product_variant_id: u16) -> SoemCode {
12 ((mfg_id as u32) << 16) | (product_variant_id as u32)
13}
14pub fn soem_code_mfg(sc: SoemCode) -> u16 { (sc >> 16) as u16 }
15pub fn soem_code_variant(sc: SoemCode) -> u16 { sc as u16 }
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum SigNetError {
19 InvalidArgument,
20 BufferFull,
21 Crypto,
22 Encode,
23 Network,
24 BufferTooSmall,
25 InvalidPacket,
26 InvalidOption,
27 HmacFailed,
28 TestFailure,
29 PassphraseTooShort,
30 PassphraseTooLong,
31 PassphraseInsufficientClasses,
32 PassphraseConsecutiveIdentical,
33 PassphraseConsecutiveSequential,
34 SessionIdOverflow,
35}
36
37impl fmt::Display for SigNetError {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 match self {
40 SigNetError::InvalidArgument => write!(f, "invalid argument"),
41 SigNetError::BufferFull => write!(f, "buffer full"),
42 SigNetError::Crypto => write!(f, "cryptographic operation failed"),
43 SigNetError::Encode => write!(f, "encoding error"),
44 SigNetError::Network => write!(f, "network error"),
45 SigNetError::BufferTooSmall => write!(f, "buffer too small"),
46 SigNetError::InvalidPacket => write!(f, "invalid packet"),
47 SigNetError::InvalidOption => write!(f, "invalid option"),
48 SigNetError::HmacFailed => write!(f, "HMAC verification failed"),
49 SigNetError::TestFailure => write!(f, "self-test failed"),
50 SigNetError::PassphraseTooShort => write!(f, "passphrase too short"),
51 SigNetError::PassphraseTooLong => write!(f, "passphrase too long"),
52 SigNetError::PassphraseInsufficientClasses => write!(f, "insufficient character classes"),
53 SigNetError::PassphraseConsecutiveIdentical => write!(f, "consecutive identical characters"),
54 SigNetError::PassphraseConsecutiveSequential => write!(f, "consecutive sequential characters"),
55 SigNetError::SessionIdOverflow => write!(f, "session ID overflow, manual intervention required"),
56 }
57 }
58}
59
60impl std::error::Error for SigNetError {}
61
62#[derive(Debug, Clone, Copy, PartialEq, Eq)]
63pub struct CoAPHeader {
64 pub version: u8,
65 pub type_: u8,
66 pub token_length: u8,
67 pub code: u8,
68 pub message_id: u16,
69}
70
71impl CoAPHeader {
72 pub const SIZE: usize = 4;
73
74 pub fn from_bytes(bytes: &[u8; 4]) -> Self {
75 CoAPHeader {
76 version: bytes[0] >> 6,
77 type_: (bytes[0] >> 4) & 0x03,
78 token_length: bytes[0] & 0x0F,
79 code: bytes[1],
80 message_id: u16::from_be_bytes([bytes[2], bytes[3]]),
81 }
82 }
83
84 pub fn to_bytes(&self) -> [u8; 4] {
85 let vtt = ((self.version & 0x03) << 6) | ((self.type_ & 0x03) << 4) | (self.token_length & 0x0F);
86 let mid = self.message_id.to_be_bytes();
87 [vtt, self.code, mid[0], mid[1]]
88 }
89
90 pub fn new(message_id: u16) -> Self {
91 CoAPHeader {
92 version: COAP_VERSION,
93 type_: COAP_TYPE_NON,
94 token_length: 0,
95 code: COAP_CODE_POST,
96 message_id,
97 }
98 }
99}
100
101#[derive(Debug, Clone, Copy)]
102pub struct TLVBlock<'a> {
103 pub type_id: u16,
104 pub value: &'a [u8],
105}
106
107impl<'a> TLVBlock<'a> {
108 pub fn length(&self) -> u16 {
109 self.value.len() as u16
110 }
111}
112
113#[derive(Debug, Clone, Default)]
114pub struct SigNetOptions {
115 pub security_mode: u8,
116 pub sender_id: [u8; SENDER_ID_LENGTH],
117 pub mfg_code: u16,
118 pub session_id: u32,
119 pub seq_num: u32,
120 pub hmac: [u8; HMAC_SHA256_LENGTH],
121}
122
123#[derive(Debug, Clone)]
124pub struct PacketBuffer {
125 buffer: [u8; MAX_UDP_PAYLOAD as usize],
126 position: u16,
127}
128
129impl PacketBuffer {
130 pub fn new() -> Self {
131 PacketBuffer {
132 buffer: [0u8; MAX_UDP_PAYLOAD as usize],
133 position: 0,
134 }
135 }
136
137 pub fn reset(&mut self) {
138 self.position = 0;
139 self.buffer.fill(0);
140 }
141
142 pub fn position(&self) -> u16 {
143 self.position
144 }
145
146 pub fn len(&self) -> u16 {
147 self.position
148 }
149
150 pub fn is_empty(&self) -> bool {
151 self.position == 0
152 }
153
154 pub fn as_slice(&self) -> &[u8] {
155 &self.buffer[..self.position as usize]
156 }
157
158 pub fn as_mut_slice(&mut self) -> &mut [u8] {
159 &mut self.buffer[..self.position as usize]
160 }
161
162 pub fn remaining(&self) -> u16 {
163 MAX_UDP_PAYLOAD - self.position
164 }
165
166 pub fn has_space(&self, size: u16) -> bool {
167 (self.position + size) <= MAX_UDP_PAYLOAD
168 }
169
170 pub fn write_byte(&mut self, value: u8) -> Result<()> {
171 if !self.has_space(1) {
172 return Err(SigNetError::BufferFull);
173 }
174 self.buffer[self.position as usize] = value;
175 self.position += 1;
176 Ok(())
177 }
178
179 pub fn write_bytes(&mut self, data: &[u8]) -> Result<()> {
180 let len = data.len() as u16;
181 if !self.has_space(len) {
182 return Err(SigNetError::BufferFull);
183 }
184 let pos = self.position as usize;
185 self.buffer[pos..pos + data.len()].copy_from_slice(data);
186 self.position += len;
187 Ok(())
188 }
189
190 pub fn write_u16(&mut self, value: u16) -> Result<()> {
191 if !self.has_space(2) {
192 return Err(SigNetError::BufferFull);
193 }
194 let pos = self.position as usize;
195 self.buffer[pos..pos + 2].copy_from_slice(&value.to_be_bytes());
196 self.position += 2;
197 Ok(())
198 }
199
200 pub fn write_u32(&mut self, value: u32) -> Result<()> {
201 if !self.has_space(4) {
202 return Err(SigNetError::BufferFull);
203 }
204 let pos = self.position as usize;
205 self.buffer[pos..pos + 4].copy_from_slice(&value.to_be_bytes());
206 self.position += 4;
207 Ok(())
208 }
209
210 pub fn seek(&mut self, position: u16) -> Result<()> {
211 if position > MAX_UDP_PAYLOAD {
212 return Err(SigNetError::InvalidArgument);
213 }
214 self.position = position;
215 Ok(())
216 }
217
218 pub fn as_raw(&self) -> &[u8; MAX_UDP_PAYLOAD as usize] {
219 &self.buffer
220 }
221
222 pub fn as_raw_mut(&mut self) -> &mut [u8; MAX_UDP_PAYLOAD as usize] {
223 &mut self.buffer
224 }
225}
226
227impl Default for PacketBuffer {
228 fn default() -> Self {
229 Self::new()
230 }
231}
232
233#[derive(Debug, Clone, Default)]
234pub struct ReceiverSenderState {
235 pub sender_id: [u8; SENDER_ID_LENGTH],
236 pub session_id: u32,
237 pub seq_num: u32,
238 pub last_packet_time_ms: u32,
239 pub total_packets_received: u32,
240 pub total_packets_accepted: u32,
241}
242
243#[derive(Debug, Clone, Default)]
244pub struct ReceiverStatistics {
245 pub total_packets: u32,
246 pub accepted_packets: u32,
247 pub coap_version_errors: u32,
248 pub coap_type_errors: u32,
249 pub coap_code_errors: u32,
250 pub uri_mismatches: u32,
251 pub missing_options: u32,
252 pub hmac_failures: u32,
253 pub replay_detected: u32,
254 pub parse_errors: u32,
255 pub last_packet_time_ms: u32,
256}
257
258#[derive(Debug, Clone, Default)]
259pub struct ReceivedPacketInfo {
260 pub message_id: u16,
261 pub sender_tuid: [u8; TUID_LENGTH],
262 pub endpoint: u16,
263 pub soem_code: SoemCode,
264 pub session_id: u32,
265 pub seq_num: u32,
266 pub dmx_slot_count: u16,
267 pub hmac_valid: bool,
268 pub session_fresh: bool,
269 pub rejection_reason: Option<&'static str>,
270 pub timestamp_ms: u32,
271}
272
273#[derive(Debug, Clone, Copy, PartialEq, Eq)]
274pub struct TUID(pub [u8; TUID_LENGTH]);
275
276impl TUID {
277 pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
278 if bytes.len() != TUID_LENGTH {
279 return Err(SigNetError::InvalidArgument);
280 }
281 let mut arr = [0u8; TUID_LENGTH];
282 arr.copy_from_slice(bytes);
283 Ok(TUID(arr))
284 }
285
286 pub fn as_bytes(&self) -> &[u8] {
287 &self.0
288 }
289
290 pub fn to_hex_upper(&self) -> [u8; TUID_HEX_LENGTH] {
292 const HEX_CHARS: &[u8; 16] = b"0123456789ABCDEF";
293 let mut out = [0u8; TUID_HEX_LENGTH];
294 for i in 0..TUID_LENGTH {
295 out[i * 2] = HEX_CHARS[(self.0[i] >> 4) as usize];
296 out[i * 2 + 1] = HEX_CHARS[(self.0[i] & 0x0F) as usize];
297 }
298 out
299 }
300
301 pub fn to_hex_display(&self) -> [u8; TUID_HEX_LENGTH] {
303 const HEX_CHARS: &[u8; 16] = b"0123456789ABCDEF";
304 let mut out = [0u8; TUID_HEX_LENGTH];
305 for i in 0..TUID_LENGTH {
306 out[i * 2] = HEX_CHARS[(self.0[i] >> 4) as usize];
307 out[i * 2 + 1] = HEX_CHARS[(self.0[i] & 0x0F) as usize];
308 }
309 out
310 }
311
312 #[deprecated(since = "0.18.0", note = "use to_hex_display() or to_hex_upper()")]
313 pub fn to_hex(&self) -> [u8; TUID_HEX_LENGTH] {
314 self.to_hex_display()
315 }
316
317 pub fn from_hex(hex: &[u8]) -> Result<Self> {
318 if hex.len() != TUID_HEX_LENGTH {
319 return Err(SigNetError::InvalidArgument);
320 }
321 let mut arr = [0u8; TUID_LENGTH];
322 for i in 0..TUID_LENGTH {
323 arr[i] = (hex_char(hex[i * 2])? << 4) | hex_char(hex[i * 2 + 1])?;
324 }
325 Ok(TUID(arr))
326 }
327}
328
329pub fn increment_sequence(current_seq: u32) -> u32 {
330 if current_seq == 0xFFFFFFFF {
331 1
332 } else {
333 current_seq + 1
334 }
335}
336
337pub fn should_increment_session(seq_num: u32) -> bool {
338 seq_num == 0xFFFFFFFF
339}
340
341pub fn calculate_multicast_address(universe: u16) -> Result<[u8; 4]> {
342 if !(MIN_UNIVERSE..=MAX_UNIVERSE).contains(&universe) {
343 return Err(SigNetError::InvalidArgument);
344 }
345 let index = ((universe - 1) % 100) + 1;
346 Ok([MULTICAST_BASE_OCTET_0, MULTICAST_BASE_OCTET_1, MULTICAST_BASE_OCTET_2, index as u8])
347}