mbus_core/models/diagnostic/
model.rs1use crate::{data_unit::common::MAX_PDU_DATA_LEN, errors::MbusError};
31use core::fmt;
32use heapless::Vec;
33
34#[derive(Debug, Clone, PartialEq)]
36pub struct DeviceIdObject {
37 pub object_id: ObjectId,
39 pub value: Vec<u8, MAX_PDU_DATA_LEN>,
41}
42
43pub struct DeviceIdObjectIterator<'a> {
48 pub(crate) data: &'a [u8],
50 offset: usize,
52 count: u8,
54 total: u8,
56}
57
58impl<'a> Iterator for DeviceIdObjectIterator<'a> {
59 type Item = Result<DeviceIdObject, MbusError>;
60
61 fn next(&mut self) -> Option<Self::Item> {
63 if self.count >= self.total {
64 return None;
65 }
66
67 self.parse_next()
70 }
71}
72
73impl<'a> DeviceIdObjectIterator<'a> {
74 fn parse_next(&mut self) -> Option<Result<DeviceIdObject, MbusError>> {
81 if self.offset + 2 > self.data.len() {
83 return Some(Err(MbusError::InvalidPduLength));
84 }
85 let obj_id = ObjectId::from(self.data[self.offset]);
86 let obj_len = self.data[self.offset + 1] as usize;
87 self.offset += 2; if self.offset + obj_len > self.data.len() {
91 return Some(Err(MbusError::InvalidPduLength));
92 }
93
94 let mut value = Vec::new();
95 if value
97 .extend_from_slice(&self.data[self.offset..self.offset + obj_len])
98 .is_err()
99 {
100 return Some(Err(MbusError::BufferTooSmall));
101 }
102
103 self.offset += obj_len;
104 self.count += 1;
105
106 Some(Ok(DeviceIdObject {
107 object_id: obj_id,
108 value,
109 }))
110 }
111}
112
113#[derive(Debug, Clone, PartialEq)]
115pub struct DeviceIdentificationResponse {
116 pub read_device_id_code: ReadDeviceIdCode,
118 pub conformity_level: ConformityLevel,
120 pub more_follows: bool,
122 pub next_object_id: ObjectId,
124 pub objects_data: [u8; MAX_PDU_DATA_LEN],
126 pub number_of_objects: u8,
128}
129
130impl DeviceIdentificationResponse {
131 pub fn objects(&self) -> DeviceIdObjectIterator<'_> {
133 DeviceIdObjectIterator {
134 data: &self.objects_data,
135 offset: 0,
136 count: 0,
137 total: self.number_of_objects,
138 }
139 }
140}
141
142#[derive(Debug, Clone, Copy, PartialEq, Eq)]
147#[repr(u8)]
148pub enum BasicObjectId {
149 VendorName = 0x00,
151 ProductCode = 0x01,
153 MajorMinorRevision = 0x02,
155}
156
157impl TryFrom<u8> for BasicObjectId {
158 type Error = MbusError;
159
160 fn try_from(value: u8) -> Result<Self, Self::Error> {
161 match value {
162 0x00 => Ok(BasicObjectId::VendorName),
163 0x01 => Ok(BasicObjectId::ProductCode),
164 0x02 => Ok(BasicObjectId::MajorMinorRevision),
165 _ => Err(MbusError::InvalidAddress),
166 }
167 }
168}
169
170impl fmt::Display for BasicObjectId {
171 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
172 match self {
173 BasicObjectId::VendorName => write!(f, "VendorName"),
174 BasicObjectId::ProductCode => write!(f, "ProductCode"),
175 BasicObjectId::MajorMinorRevision => write!(f, "MajorMinorRevision"),
176 }
177 }
178}
179
180#[derive(Debug, Clone, Copy, PartialEq, Eq)]
185#[repr(u8)]
186pub enum RegularObjectId {
187 VendorUrl = 0x03,
189 ProductName = 0x04,
191 ModelName = 0x05,
193 UserApplicationName = 0x06,
195}
196
197impl TryFrom<u8> for RegularObjectId {
198 type Error = MbusError;
199
200 fn try_from(value: u8) -> Result<Self, Self::Error> {
201 match value {
202 0x03 => Ok(RegularObjectId::VendorUrl),
203 0x04 => Ok(RegularObjectId::ProductName),
204 0x05 => Ok(RegularObjectId::ModelName),
205 0x06 => Ok(RegularObjectId::UserApplicationName),
206 _ => Err(MbusError::InvalidAddress),
207 }
208 }
209}
210
211impl fmt::Display for RegularObjectId {
212 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
213 match self {
214 RegularObjectId::VendorUrl => write!(f, "VendorUrl"),
215 RegularObjectId::ProductName => write!(f, "ProductName"),
216 RegularObjectId::ModelName => write!(f, "ModelName"),
217 RegularObjectId::UserApplicationName => write!(f, "UserApplicationName"),
218 }
219 }
220}
221
222#[derive(Debug, Clone, Copy, PartialEq, Eq)]
227pub struct ExtendedObjectId(u8);
228
229impl ExtendedObjectId {
230 pub fn new(id: u8) -> Option<Self> {
234 if (0x80..=0xFF).contains(&id) {
235 Some(Self(id))
236 } else {
237 None
238 }
239 }
240
241 pub fn value(&self) -> u8 {
243 self.0
244 }
245}
246
247#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
251#[repr(u8)]
252pub enum ReadDeviceIdCode {
253 #[default]
256 Err,
257 Basic = 0x01,
259 Regular = 0x02,
261 Extended = 0x03,
263 Specific = 0x04,
265}
266
267impl TryFrom<u8> for ReadDeviceIdCode {
268 type Error = MbusError;
269
270 fn try_from(value: u8) -> Result<Self, Self::Error> {
271 match value {
272 0x01 => Ok(ReadDeviceIdCode::Basic),
273 0x02 => Ok(ReadDeviceIdCode::Regular),
274 0x03 => Ok(ReadDeviceIdCode::Extended),
275 0x04 => Ok(ReadDeviceIdCode::Specific),
276 _ => Err(MbusError::InvalidDeviceIdCode),
277 }
278 }
279}
280
281#[derive(Debug, Clone, Copy, PartialEq, Eq)]
283#[repr(u8)]
284pub enum ConformityLevel {
285 BasicStreamOnly = 0x01,
287 RegularStreamOnly = 0x02,
289 ExtendedStreamOnly = 0x03,
291 BasicStreamAndIndividual = 0x81,
293 RegularStreamAndIndividual = 0x82,
295 ExtendedStreamAndIndividual = 0x83,
297}
298
299impl TryFrom<u8> for ConformityLevel {
300 type Error = MbusError;
301
302 fn try_from(value: u8) -> Result<Self, Self::Error> {
303 match value {
304 0x01 => Ok(ConformityLevel::BasicStreamOnly),
305 0x02 => Ok(ConformityLevel::RegularStreamOnly),
306 0x03 => Ok(ConformityLevel::ExtendedStreamOnly),
307 0x81 => Ok(ConformityLevel::BasicStreamAndIndividual),
308 0x82 => Ok(ConformityLevel::RegularStreamAndIndividual),
309 0x83 => Ok(ConformityLevel::ExtendedStreamAndIndividual),
310 _ => Err(MbusError::ParseError),
311 }
312 }
313}
314
315#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
317pub enum ObjectId {
318 #[default]
321 Err,
322 Basic(BasicObjectId),
324 Regular(RegularObjectId),
326 Extended(ExtendedObjectId),
328 Reserved(u8),
330}
331
332impl From<u8> for ObjectId {
333 fn from(id: u8) -> Self {
334 if let Ok(basic) = BasicObjectId::try_from(id) {
335 ObjectId::Basic(basic)
336 } else if let Ok(regular) = RegularObjectId::try_from(id) {
337 ObjectId::Regular(regular)
338 } else if let Some(extended) = ExtendedObjectId::new(id) {
339 ObjectId::Extended(extended)
340 } else {
341 ObjectId::Reserved(id)
342 }
343 }
344}
345
346impl fmt::Display for ObjectId {
347 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
348 match self {
349 ObjectId::Basic(id) => write!(f, "Basic({})", id),
350 ObjectId::Regular(id) => write!(f, "Regular({})", id),
351 ObjectId::Extended(id) => write!(f, "Extended({:#04X})", id.value()),
352 ObjectId::Reserved(id) => write!(f, "Reserved({:#04X})", id),
353 ObjectId::Err => write!(f, "Err (sentinel default)"),
354 }
355 }
356}
357
358impl From<ObjectId> for u8 {
359 fn from(oid: ObjectId) -> u8 {
360 match oid {
361 ObjectId::Basic(id) => id as u8,
362 ObjectId::Regular(id) => id as u8,
363 ObjectId::Extended(id) => id.value(),
364 ObjectId::Reserved(id) => id,
365 ObjectId::Err => 0, }
367 }
368}