1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//! Wired M-Bus data-link fields and frame codecs.
//!
//! This crate represents and encodes the wired M-Bus frames exchanged by
//! masters and slaves. Its wire formats and message types follow the
//! link-layer portion of EN 13757-2:2018+A1:2023, which uses the FT1.2 format
//! class defined by the EN 60870-5 series.
//!
//! The API is suitable for M-Bus masters, meters, bridges, and diagnostic
//! tools. It is [`no_std`](https://doc.rust-lang.org/reference/names/preludes.html#the-no_std-attribute)
//! and supports encoding without dynamic allocation.
//!
//! # Scope
//!
//! The crate provides:
//!
//! - typed control and address fields;
//! - ACK and NACK acknowledgement frames;
//! - fixed-length short frames;
//! - variable-format control frames without user data; and
//! - variable-format long frames containing user data.
//!
//! Constructors and decoders validate each frame's structure, checksum, and
//! supported control-field use. Address values remain representable even when
//! they are reserved or inappropriate for a particular exchange; callers can
//! inspect [`Address::kind`] and [`Address::expects_response`] when applying
//! protocol rules.
//!
//! This crate does **not** implement:
//!
//! - the wired electrical interface or UART configuration;
//! - byte timing, collision handling, retries, or response timeouts;
//! - master or slave state machines;
//! - application-layer interpretation of the control-information byte or user
//! data.
//!
//! Those concerns belong to the surrounding physical, transport, and
//! application layers. In particular, application data carried by a
//! [`LongFrame`] is specified separately by EN 13757-3.
//!
//! # Choosing a frame
//!
//! | Type | Wire form | Typical role |
//! | --- | --- | --- |
//! | [`AckFrame`] | One byte, `0xe5` | Positively acknowledge an accepted request |
//! | [`NackFrame`] | One byte, `0xa2` | Reject an unsupported SND-UD2 request |
//! | [`ShortFrame`] | Five-byte fixed format | Send SND-NKE, REQ-UD1, or REQ-UD2 |
//! | [`ControlFrame`] | Nine-byte variable format with no user data | Carry control and control-information fields without an application payload |
//! | [`LongFrame`] | Variable format with 1 to 252 user-data bytes | Send or respond with application data |
//!
//! A frame constructor rejects a [`Control`] value that is incompatible with
//! that frame format. [`CommunicationType`] identifies the supported
//! communication type represented by a raw control field.
//!
//! # Encoding and decoding
//!
//! Every `decode` function consumes a slice containing exactly one complete
//! frame. It rejects truncated input, trailing bytes, invalid delimiters,
//! invalid lengths, checksum mismatches, and incompatible control fields as
//! applicable to that frame type. [`decoder::stream`] identifies boundaries
//! across arbitrary chunks and can recover from noise without allocation.
//!
//! Every frame provides `encode_into`, which writes into a caller-owned buffer
//! and returns only the initialized portion. When the `alloc` feature is
//! enabled, frames also provide `encode`, which returns an allocated
//! `Vec`.
//!
//! # Example
//!
//! The following constructs the standard five-byte shape of a REQ-UD2 request
//! for slave address 1, encodes it without allocation, and decodes it again:
//!
//! ```
//! use meterbus_wired_datalink::{Address, Control, ShortFrame};
//!
//! # fn main() -> Result<(), meterbus_wired_datalink::ShortFrameError> {
//! let request = ShortFrame::new(Control::req_ud2(false), Address::new(1))?;
//! let mut storage = [0_u8; ShortFrame::LEN];
//! let encoded = request.encode_into(&mut storage)?;
//!
//! assert_eq!(encoded, [0x10, 0x5b, 0x01, 0x5c, 0x16]);
//! assert_eq!(ShortFrame::decode(encoded)?, request);
//! # Ok(())
//! # }
//! ```
//!
//! # Allocation and crate features
//!
//! The crate itself always uses `#![no_std]`.
//!
//! - the default feature set is allocation-free;
//! - `alloc` adds allocating `encode` methods and the collecting
//! `decoder::stream::StreamDecoder::push` convenience method.
//!
//! Without `alloc`, encode with `encode_into` and stream with `push_into`.
//!
//! A valid frame is not necessarily the right frame for the current exchange.
//! Callers must still manage message order, timing, retries, and application
//! data according to EN 13757-2 and EN 13757-3.
extern crate alloc;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;