meterbus_wired_datalink/frame/field/address.rs
1//! Wired M-Bus configured-slave and special-purpose data-link addresses.
2//!
3//! Every structured wired M-Bus frame contains a one-byte address field. Most
4//! values identify one configured slave, while values near the ends of the
5//! address space select protocol-defined modes such as unconfigured-slave
6//! access, selected-slave addressing, diagnosis, and broadcast.
7//!
8//! [`Address`] preserves the byte read from the wire. [`AddressKind`] explains
9//! how that value is used. Keeping both lets decoders and diagnostic tools
10//! report reserved or unexpected addresses clearly.
11//!
12//! # Address space
13//!
14//! | Value | [`AddressKind`] | Meaning | Response generally expected |
15//! | --- | --- | --- | --- |
16//! | `0` | [`AddressKind::Unconfigured`] | All unconfigured slaves | Yes |
17//! | `1..=250` | [`AddressKind::Primary`] | One configured slave | Yes |
18//! | `251` | [`AddressKind::PrimaryMasterRepeater`] | Primary-master repeater management | Yes |
19//! | `252` | [`AddressKind::Reserved`] | Reserved | No |
20//! | `253` | [`AddressKind::Secondary`] | Previously selected slave or slaves | Yes |
21//! | `254` | [`AddressKind::Test`] | Test and diagnosis | Yes |
22//! | `255` | [`AddressKind::Broadcast`] | All slaves | No |
23//!
24//! [`Address::expects_response`] implements the final column: it returns
25//! `false` only for the reserved and broadcast classes. It describes the
26//! address-level rule, not a guarantee that a particular request has a reply.
27//! The communication type, device capabilities, bus state, and transmission
28//! success can all affect whether a response is actually observed.
29//!
30//! Address 253 refers to slaves selected by an earlier application-layer
31//! operation; it does not contain their identity. Address 255 is broadcast, so
32//! slaves do not reply. Reserved values remain representable for diagnostics.
33//!
34//! # Examples
35//!
36//! Classify an ordinary configured-slave address:
37//!
38//! ```
39//! use meterbus_wired_datalink::{Address, AddressKind};
40//!
41//! let address = Address::new(42);
42//! assert_eq!(address.value(), 42);
43//! assert_eq!(address.kind(), AddressKind::Primary);
44//! assert!(address.expects_response());
45//! ```
46//!
47//! Detect a broadcast before waiting for a reply:
48//!
49//! ```
50//! use meterbus_wired_datalink::{Address, AddressKind};
51//!
52//! let address = Address::from(0xff);
53//! assert_eq!(address.kind(), AddressKind::Broadcast);
54//! assert!(!address.expects_response());
55//! ```
56//!
57//! Frame constructors do not reject reserved or special-purpose addresses. The
58//! caller decides whether an address is valid for the current operation.
59
60/// A data-link address.
61#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
62pub struct Address(u8);
63
64impl Address {
65 /// Creates an address from its wire value.
66 #[must_use]
67 pub const fn new(value: u8) -> Self {
68 Self(value)
69 }
70
71 /// Returns the wire value.
72 #[must_use]
73 pub const fn value(self) -> u8 {
74 self.0
75 }
76
77 /// Classifies the address according to EN 13757-2.
78 #[must_use]
79 pub const fn kind(self) -> AddressKind {
80 match self.0 {
81 0 => AddressKind::Unconfigured,
82 1..=250 => AddressKind::Primary,
83 251 => AddressKind::PrimaryMasterRepeater,
84 252 => AddressKind::Reserved,
85 253 => AddressKind::Secondary,
86 254 => AddressKind::Test,
87 255 => AddressKind::Broadcast,
88 }
89 }
90
91 /// Returns whether a slave response may be expected.
92 #[must_use]
93 pub const fn expects_response(self) -> bool {
94 !matches!(self.kind(), AddressKind::Reserved | AddressKind::Broadcast)
95 }
96}
97
98impl From<u8> for Address {
99 fn from(value: u8) -> Self {
100 Self::new(value)
101 }
102}
103
104/// The protocol-defined use of a data-link address.
105#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
106pub enum AddressKind {
107 /// Address 0, used by unconfigured slaves.
108 Unconfigured,
109 /// Configured slave address in the range 1 through 250.
110 Primary,
111 /// Address 251, used for primary-master repeater management.
112 PrimaryMasterRepeater,
113 /// Reserved address 252.
114 Reserved,
115 /// Address 253, used to address a previously selected slave.
116 Secondary,
117 /// Address 254, used for testing and diagnosis.
118 Test,
119 /// Broadcast address 255.
120 Broadcast,
121}
122
123#[cfg(test)]
124#[cfg_attr(coverage_nightly, coverage(off))]
125mod tests {
126 use super::*;
127
128 #[test]
129 fn classifies_every_address_range() {
130 let cases = [
131 (0, AddressKind::Unconfigured, true),
132 (1, AddressKind::Primary, true),
133 (250, AddressKind::Primary, true),
134 (251, AddressKind::PrimaryMasterRepeater, true),
135 (252, AddressKind::Reserved, false),
136 (253, AddressKind::Secondary, true),
137 (254, AddressKind::Test, true),
138 (255, AddressKind::Broadcast, false),
139 ];
140
141 for (value, kind, expects_response) in cases {
142 let address = Address::from(value);
143 assert_eq!(address.value(), value);
144 assert_eq!(address.kind(), kind);
145 assert_eq!(address.expects_response(), expects_response);
146 }
147 }
148
149 #[test]
150 fn reserved_address_remains_representable() {
151 assert_eq!(Address::new(252).value(), 252);
152 assert_eq!(Address::new(252).kind(), AddressKind::Reserved);
153 }
154}