1use std::fmt;
7use std::str::FromStr;
8
9use serde::{Deserialize, Serialize};
10
11use crate::error::KnxError;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
26pub struct IndividualAddress {
27 area: u8,
29 line: u8,
31 device: u8,
33}
34
35impl IndividualAddress {
36 pub const MAX_AREA: u8 = 15;
38 pub const MAX_LINE: u8 = 15;
40 pub const MAX_DEVICE: u8 = 255;
42
43 pub fn new(area: u8, line: u8, device: u8) -> Self {
48 assert!(area <= Self::MAX_AREA, "Area must be 0-15");
49 assert!(line <= Self::MAX_LINE, "Line must be 0-15");
50 Self { area, line, device }
51 }
52
53 pub fn try_new(area: u8, line: u8, device: u8) -> Result<Self, KnxError> {
55 if area > Self::MAX_AREA {
56 return Err(KnxError::AddressOutOfRange {
57 address: format!("area={}", area),
58 valid_range: "0-15".to_string(),
59 });
60 }
61 if line > Self::MAX_LINE {
62 return Err(KnxError::AddressOutOfRange {
63 address: format!("line={}", line),
64 valid_range: "0-15".to_string(),
65 });
66 }
67 Ok(Self { area, line, device })
68 }
69
70 #[inline]
72 pub fn area(&self) -> u8 {
73 self.area
74 }
75
76 #[inline]
78 pub fn line(&self) -> u8 {
79 self.line
80 }
81
82 #[inline]
84 pub fn device(&self) -> u8 {
85 self.device
86 }
87
88 #[inline]
90 pub fn encode(&self) -> u16 {
91 ((self.area as u16) << 12) | ((self.line as u16) << 8) | (self.device as u16)
92 }
93
94 #[inline]
96 pub fn decode(value: u16) -> Self {
97 Self {
98 area: ((value >> 12) & 0x0F) as u8,
99 line: ((value >> 8) & 0x0F) as u8,
100 device: (value & 0xFF) as u8,
101 }
102 }
103
104 pub fn to_bytes(&self) -> [u8; 2] {
106 self.encode().to_be_bytes()
107 }
108
109 pub fn from_bytes(bytes: [u8; 2]) -> Self {
111 Self::decode(u16::from_be_bytes(bytes))
112 }
113
114 #[inline]
116 pub fn is_broadcast(&self) -> bool {
117 self.area == 0 && self.line == 0 && self.device == 0
118 }
119
120 #[inline]
122 pub fn is_valid_device(&self) -> bool {
123 !self.is_broadcast()
124 }
125}
126
127impl Default for IndividualAddress {
128 fn default() -> Self {
129 Self::new(1, 1, 1)
130 }
131}
132
133impl fmt::Display for IndividualAddress {
134 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135 write!(f, "{}.{}.{}", self.area, self.line, self.device)
136 }
137}
138
139impl FromStr for IndividualAddress {
140 type Err = KnxError;
141
142 fn from_str(s: &str) -> Result<Self, Self::Err> {
143 let parts: Vec<&str> = s.split('.').collect();
144 if parts.len() != 3 {
145 return Err(KnxError::InvalidIndividualAddress(format!(
146 "Expected format 'area.line.device', got '{}'",
147 s
148 )));
149 }
150
151 let area: u8 = parts[0]
152 .parse()
153 .map_err(|_| KnxError::InvalidIndividualAddress(format!("Invalid area: {}", parts[0])))?;
154 let line: u8 = parts[1]
155 .parse()
156 .map_err(|_| KnxError::InvalidIndividualAddress(format!("Invalid line: {}", parts[1])))?;
157 let device: u8 = parts[2].parse().map_err(|_| {
158 KnxError::InvalidIndividualAddress(format!("Invalid device: {}", parts[2]))
159 })?;
160
161 Self::try_new(area, line, device)
162 .map_err(|_| KnxError::InvalidIndividualAddress(s.to_string()))
163 }
164}
165
166impl From<u16> for IndividualAddress {
167 fn from(value: u16) -> Self {
168 Self::decode(value)
169 }
170}
171
172impl From<IndividualAddress> for u16 {
173 fn from(addr: IndividualAddress) -> Self {
174 addr.encode()
175 }
176}
177
178#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
194pub struct GroupAddress {
195 raw: u16,
196}
197
198impl GroupAddress {
199 pub const MAX_MAIN: u8 = 31;
201 pub const MAX_MIDDLE: u8 = 7;
203 pub const MAX_SUB: u8 = 255;
205
206 pub fn three_level(main: u8, middle: u8, sub: u8) -> Self {
211 assert!(main <= Self::MAX_MAIN, "Main must be 0-31");
212 assert!(middle <= Self::MAX_MIDDLE, "Middle must be 0-7");
213
214 let raw =
215 ((main as u16 & 0x1F) << 11) | ((middle as u16 & 0x07) << 8) | (sub as u16 & 0xFF);
216 Self { raw }
217 }
218
219 pub fn try_three_level(main: u8, middle: u8, sub: u8) -> Result<Self, KnxError> {
221 if main > Self::MAX_MAIN {
222 return Err(KnxError::AddressOutOfRange {
223 address: format!("main={}", main),
224 valid_range: "0-31".to_string(),
225 });
226 }
227 if middle > Self::MAX_MIDDLE {
228 return Err(KnxError::AddressOutOfRange {
229 address: format!("middle={}", middle),
230 valid_range: "0-7".to_string(),
231 });
232 }
233 Ok(Self::three_level(main, middle, sub))
234 }
235
236 pub fn two_level(main: u8, sub: u16) -> Self {
238 assert!(main <= Self::MAX_MAIN, "Main must be 0-31");
239 assert!(sub <= 0x07FF, "Sub must be 0-2047");
240
241 let raw = ((main as u16 & 0x1F) << 11) | (sub & 0x07FF);
242 Self { raw }
243 }
244
245 #[inline]
247 pub fn from_raw(raw: u16) -> Self {
248 Self { raw }
249 }
250
251 #[inline]
253 pub fn raw(&self) -> u16 {
254 self.raw
255 }
256
257 pub fn as_three_level(&self) -> (u8, u8, u8) {
259 let main = ((self.raw >> 11) & 0x1F) as u8;
260 let middle = ((self.raw >> 8) & 0x07) as u8;
261 let sub = (self.raw & 0xFF) as u8;
262 (main, middle, sub)
263 }
264
265 pub fn as_two_level(&self) -> (u8, u16) {
267 let main = ((self.raw >> 11) & 0x1F) as u8;
268 let sub = self.raw & 0x07FF;
269 (main, sub)
270 }
271
272 #[inline]
274 pub fn main(&self) -> u8 {
275 ((self.raw >> 11) & 0x1F) as u8
276 }
277
278 #[inline]
280 pub fn middle(&self) -> u8 {
281 ((self.raw >> 8) & 0x07) as u8
282 }
283
284 #[inline]
286 pub fn sub(&self) -> u8 {
287 (self.raw & 0xFF) as u8
288 }
289
290 pub fn to_bytes(&self) -> [u8; 2] {
292 self.raw.to_be_bytes()
293 }
294
295 pub fn from_bytes(bytes: [u8; 2]) -> Self {
297 Self {
298 raw: u16::from_be_bytes(bytes),
299 }
300 }
301
302 #[inline]
304 pub fn is_zero(&self) -> bool {
305 self.raw == 0
306 }
307
308 pub fn format_three_level(&self) -> String {
310 let (main, middle, sub) = self.as_three_level();
311 format!("{}/{}/{}", main, middle, sub)
312 }
313
314 pub fn format_two_level(&self) -> String {
316 let (main, sub) = self.as_two_level();
317 format!("{}/{}", main, sub)
318 }
319}
320
321impl Default for GroupAddress {
322 fn default() -> Self {
323 Self::three_level(0, 0, 1)
324 }
325}
326
327impl fmt::Display for GroupAddress {
328 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
329 let (main, middle, sub) = self.as_three_level();
330 write!(f, "{}/{}/{}", main, middle, sub)
331 }
332}
333
334impl FromStr for GroupAddress {
335 type Err = KnxError;
336
337 fn from_str(s: &str) -> Result<Self, Self::Err> {
338 let parts: Vec<&str> = s.split('/').collect();
339
340 match parts.len() {
341 3 => {
343 let main: u8 = parts[0].parse().map_err(|_| {
344 KnxError::InvalidGroupAddress(format!("Invalid main group: {}", parts[0]))
345 })?;
346 let middle: u8 = parts[1].parse().map_err(|_| {
347 KnxError::InvalidGroupAddress(format!("Invalid middle group: {}", parts[1]))
348 })?;
349 let sub: u8 = parts[2].parse().map_err(|_| {
350 KnxError::InvalidGroupAddress(format!("Invalid sub group: {}", parts[2]))
351 })?;
352 Self::try_three_level(main, middle, sub)
353 }
354 2 => {
356 let main: u8 = parts[0].parse().map_err(|_| {
357 KnxError::InvalidGroupAddress(format!("Invalid main group: {}", parts[0]))
358 })?;
359 let sub: u16 = parts[1].parse().map_err(|_| {
360 KnxError::InvalidGroupAddress(format!("Invalid sub group: {}", parts[1]))
361 })?;
362 if main > Self::MAX_MAIN {
363 return Err(KnxError::AddressOutOfRange {
364 address: format!("main={}", main),
365 valid_range: "0-31".to_string(),
366 });
367 }
368 if sub > 0x07FF {
369 return Err(KnxError::AddressOutOfRange {
370 address: format!("sub={}", sub),
371 valid_range: "0-2047".to_string(),
372 });
373 }
374 Ok(Self::two_level(main, sub))
375 }
376 1 => {
378 let raw: u16 = parts[0]
379 .parse()
380 .map_err(|_| KnxError::InvalidGroupAddress(s.to_string()))?;
381 Ok(Self::from_raw(raw))
382 }
383 _ => Err(KnxError::InvalidGroupAddress(format!(
384 "Invalid format: expected 'main/middle/sub', 'main/sub', or raw value, got '{}'",
385 s
386 ))),
387 }
388 }
389}
390
391impl From<u16> for GroupAddress {
392 fn from(value: u16) -> Self {
393 Self::from_raw(value)
394 }
395}
396
397impl From<GroupAddress> for u16 {
398 fn from(addr: GroupAddress) -> Self {
399 addr.raw()
400 }
401}
402
403#[derive(Debug, Clone, Copy, PartialEq, Eq)]
409pub enum AddressType {
410 Individual,
412 Group,
414}
415
416impl AddressType {
417 #[inline]
419 pub fn from_bit(bit: bool) -> Self {
420 if bit {
421 Self::Group
422 } else {
423 Self::Individual
424 }
425 }
426
427 #[inline]
429 pub fn to_bit(&self) -> bool {
430 matches!(self, Self::Group)
431 }
432}
433
434#[derive(Debug, Clone, PartialEq, Eq)]
440pub struct GroupAddressRange {
441 start: GroupAddress,
442 end: GroupAddress,
443}
444
445impl GroupAddressRange {
446 pub fn new(start: GroupAddress, end: GroupAddress) -> Self {
448 Self { start, end }
449 }
450
451 pub fn contains(&self, addr: &GroupAddress) -> bool {
453 addr.raw() >= self.start.raw() && addr.raw() <= self.end.raw()
454 }
455
456 pub fn iter(&self) -> impl Iterator<Item = GroupAddress> {
458 (self.start.raw()..=self.end.raw()).map(GroupAddress::from_raw)
459 }
460
461 pub fn len(&self) -> usize {
463 (self.end.raw() - self.start.raw() + 1) as usize
464 }
465
466 pub fn is_empty(&self) -> bool {
468 self.start.raw() > self.end.raw()
469 }
470}
471
472#[cfg(test)]
473mod tests {
474 use super::*;
475
476 #[test]
481 fn test_individual_address_new() {
482 let addr = IndividualAddress::new(1, 2, 3);
483 assert_eq!(addr.area(), 1);
484 assert_eq!(addr.line(), 2);
485 assert_eq!(addr.device(), 3);
486 }
487
488 #[test]
489 fn test_individual_address_encode_decode() {
490 let addr = IndividualAddress::new(15, 15, 255);
491 let encoded = addr.encode();
492 let decoded = IndividualAddress::decode(encoded);
493 assert_eq!(addr, decoded);
494 }
495
496 #[test]
497 fn test_individual_address_display() {
498 let addr = IndividualAddress::new(1, 2, 3);
499 assert_eq!(addr.to_string(), "1.2.3");
500 }
501
502 #[test]
503 fn test_individual_address_parse() {
504 let addr: IndividualAddress = "1.2.3".parse().unwrap();
505 assert_eq!(addr.area(), 1);
506 assert_eq!(addr.line(), 2);
507 assert_eq!(addr.device(), 3);
508 }
509
510 #[test]
511 fn test_individual_address_parse_invalid() {
512 assert!("1.2".parse::<IndividualAddress>().is_err());
513 assert!("1.2.3.4".parse::<IndividualAddress>().is_err());
514 assert!("a.b.c".parse::<IndividualAddress>().is_err());
515 assert!("16.0.0".parse::<IndividualAddress>().is_err()); }
517
518 #[test]
519 fn test_individual_address_bytes() {
520 let addr = IndividualAddress::new(1, 2, 3);
521 let bytes = addr.to_bytes();
522 let decoded = IndividualAddress::from_bytes(bytes);
523 assert_eq!(addr, decoded);
524 }
525
526 #[test]
531 fn test_group_address_three_level() {
532 let addr = GroupAddress::three_level(1, 2, 3);
533 let (main, middle, sub) = addr.as_three_level();
534 assert_eq!(main, 1);
535 assert_eq!(middle, 2);
536 assert_eq!(sub, 3);
537 }
538
539 #[test]
540 fn test_group_address_two_level() {
541 let addr = GroupAddress::two_level(1, 515);
542 let (main, sub) = addr.as_two_level();
543 assert_eq!(main, 1);
544 assert_eq!(sub, 515);
545 }
546
547 #[test]
548 fn test_group_address_display() {
549 let addr = GroupAddress::three_level(1, 2, 3);
550 assert_eq!(addr.to_string(), "1/2/3");
551 }
552
553 #[test]
554 fn test_group_address_parse_three_level() {
555 let addr: GroupAddress = "1/2/3".parse().unwrap();
556 assert_eq!(addr.main(), 1);
557 assert_eq!(addr.middle(), 2);
558 assert_eq!(addr.sub(), 3);
559 }
560
561 #[test]
562 fn test_group_address_parse_two_level() {
563 let addr: GroupAddress = "1/515".parse().unwrap();
564 let (main, sub) = addr.as_two_level();
565 assert_eq!(main, 1);
566 assert_eq!(sub, 515);
567 }
568
569 #[test]
570 fn test_group_address_parse_raw() {
571 let addr: GroupAddress = "12345".parse().unwrap();
572 assert_eq!(addr.raw(), 12345);
573 }
574
575 #[test]
576 fn test_group_address_bytes() {
577 let addr = GroupAddress::three_level(1, 2, 3);
578 let bytes = addr.to_bytes();
579 let decoded = GroupAddress::from_bytes(bytes);
580 assert_eq!(addr, decoded);
581 }
582
583 #[test]
588 fn test_address_range_contains() {
589 let range = GroupAddressRange::new(
590 GroupAddress::three_level(1, 0, 0),
591 GroupAddress::three_level(1, 0, 255),
592 );
593
594 assert!(range.contains(&GroupAddress::three_level(1, 0, 100)));
595 assert!(!range.contains(&GroupAddress::three_level(2, 0, 0)));
596 }
597
598 #[test]
599 fn test_address_range_len() {
600 let range = GroupAddressRange::new(
601 GroupAddress::three_level(1, 0, 0),
602 GroupAddress::three_level(1, 0, 9),
603 );
604 assert_eq!(range.len(), 10);
605 }
606}