m_bus_parser/lib.rs
1//! Brief summary
2//! * is a library for parsing M-Bus frames and user data.
3//! * aims to be a modern, open source decoder for wired m-bus protocol decoder for EN 13757-2 physical and link layer, EN 13757-3 application layer of m-bus
4//! * was implemented using the publicly available documentation available at <https://m-bus.com/>
5//! # Example
6//! ```rust
7//!
8//! use m_bus_core::{FrameError, Function};
9//! use wired_mbus_link_layer::{Address, WiredFrame};
10//! use m_bus_parser::user_data::parse_application_layer;
11//! use m_bus_parser::mbus_data::MbusData;
12//!
13//! fn try_parse() -> Result<(), m_bus_parser::MbusError> {
14//! let example = vec![
15//! 0x68, 0x4D, 0x4D, 0x68, 0x08, 0x01, 0x72, 0x01,
16//! 0x00, 0x00, 0x00, 0x96, 0x15, 0x01, 0x00, 0x18,
17//! 0x00, 0x00, 0x00, 0x0C, 0x78, 0x56, 0x00, 0x00,
18//! 0x00, 0x01, 0xFD, 0x1B, 0x00, 0x02, 0xFC, 0x03,
19//! 0x48, 0x52, 0x25, 0x74, 0x44, 0x0D, 0x22, 0xFC,
20//! 0x03, 0x48, 0x52, 0x25, 0x74, 0xF1, 0x0C, 0x12,
21//! 0xFC, 0x03, 0x48, 0x52, 0x25, 0x74, 0x63, 0x11,
22//! 0x02, 0x65, 0xB4, 0x09, 0x22, 0x65, 0x86, 0x09,
23//! 0x12, 0x65, 0xB7, 0x09, 0x01, 0x72, 0x00, 0x72,
24//! 0x65, 0x00, 0x00, 0xB2, 0x01, 0x65, 0x00, 0x00,
25//! 0x1F, 0xB3, 0x16
26//! ];
27//!
28//! // Parse the frame
29//! let frame = WiredFrame::try_from(example.as_slice())?;
30//!
31//! if let WiredFrame::LongFrame { function, address, data } = frame {
32//! assert_eq!(function, Function::RspUd { acd: false, dfc: false });
33//! assert_eq!(address, Address::Primary(1));
34//! let application_layer = parse_application_layer(data)?;
35//! if let Some(data_records) = application_layer.data_records() {
36//! println!("data_records: {:#?}", data_records.collect::<Result<Vec<_>, _>>()?);
37//! }
38//! }
39//!
40//! // Parse everything at once
41//! let parsed_data = MbusData::<WiredFrame>::try_from(example.as_slice())?;
42//! println!("parsed_data: {:#?}", parsed_data);
43//! Ok(())
44//! }
45//! ```
46
47#![cfg_attr(not(feature = "std"), no_std)]
48
49#[cfg(feature = "std")]
50#[allow(clippy::indexing_slicing)]
51pub mod annotate;
52#[cfg(feature = "std")]
53pub mod manufacturers;
54pub mod mbus_data;
55#[cfg(feature = "std")]
56mod rscada_xml;
57pub use m_bus_application_layer as user_data;
58
59pub use m_bus_core::decryption;
60use m_bus_core::ApplicationLayerError;
61// Re-export link layer types for convenience
62pub use m_bus_core::{FrameError, Function};
63pub use wired_mbus_link_layer::{Address, WiredFrame};
64pub use wireless_mbus_link_layer::{ManufacturerId, WirelessFrame};
65
66#[cfg(feature = "std")]
67pub use mbus_data::serialize_mbus_data;
68
69#[derive(Debug, Clone, Copy, PartialEq)]
70#[cfg_attr(feature = "serde", derive(serde::Serialize))]
71#[non_exhaustive]
72pub enum MbusError {
73 FrameError(FrameError),
74 WirelessFrameError(wireless_mbus_link_layer::FrameError),
75 ApplicationLayerError(ApplicationLayerError),
76 DataRecordError(user_data::variable_user_data::DataRecordError),
77}
78
79#[cfg(feature = "std")]
80impl std::fmt::Display for MbusError {
81 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
82 match self {
83 MbusError::FrameError(e) => write!(f, "{e}"),
84 MbusError::WirelessFrameError(e) => write!(f, "{:?}", e),
85 MbusError::ApplicationLayerError(e) => write!(f, "{e}"),
86 MbusError::DataRecordError(e) => write!(f, "{e}"),
87 }
88 }
89}
90
91#[cfg(feature = "std")]
92impl std::error::Error for MbusError {}
93
94impl From<FrameError> for MbusError {
95 fn from(error: FrameError) -> Self {
96 Self::FrameError(error)
97 }
98}
99
100impl From<ApplicationLayerError> for MbusError {
101 fn from(error: ApplicationLayerError) -> Self {
102 Self::ApplicationLayerError(error)
103 }
104}
105
106impl From<user_data::variable_user_data::DataRecordError> for MbusError {
107 fn from(error: user_data::variable_user_data::DataRecordError) -> Self {
108 Self::DataRecordError(error)
109 }
110}
111
112impl From<wireless_mbus_link_layer::FrameError> for MbusError {
113 fn from(error: wireless_mbus_link_layer::FrameError) -> Self {
114 Self::WirelessFrameError(error)
115 }
116}