Skip to main content

smbioslib/structs/types/
temperature_probe.rs

1use crate::core::{strings::*, UndefinedStruct};
2use crate::SMBiosStruct;
3use serde::{ser::SerializeStruct, Serialize, Serializer};
4use std::fmt;
5
6/// # Temperature Probe (Type 28)
7///
8/// This structure describes the attributes for a temperature probe in the system. Each structure describes a
9/// single temperature probe.
10///
11/// NOTE This structure type was added in version 2.2 of this specification.
12pub struct SMBiosTemperatureProbe<'a> {
13    parts: &'a UndefinedStruct,
14}
15
16impl<'a> SMBiosStruct<'a> for SMBiosTemperatureProbe<'a> {
17    const STRUCT_TYPE: u8 = 28u8;
18
19    fn new(parts: &'a UndefinedStruct) -> Self {
20        Self { parts }
21    }
22
23    fn parts(&self) -> &'a UndefinedStruct {
24        self.parts
25    }
26}
27
28impl<'a> SMBiosTemperatureProbe<'a> {
29    /// Description
30    ///
31    /// additional descriptive information about the probe or its location
32    pub fn description(&self) -> SMBiosString {
33        self.parts.get_field_string(0x04)
34    }
35
36    /// Location and status
37    ///
38    /// Probe’s physical location and the status of the temperature
39    /// monitored by this temperature probe
40    pub fn location_and_status(&self) -> Option<TemperatureProbeLocationAndStatus> {
41        self.parts
42            .get_field_byte(0x05)
43            .map(|raw| TemperatureProbeLocationAndStatus::from(raw))
44    }
45
46    /// Maximum value
47    ///
48    /// Maximum temperature readable by this probe, in 1/10th degrees C
49    ///
50    /// If the value is unknown, the field is set to 0x8000.
51    pub fn maximum_value(&self) -> Option<ProbeTemperature> {
52        self.parts
53            .get_field_word(0x06)
54            .map(|raw| ProbeTemperature::from(raw))
55    }
56
57    /// Minimum value
58    ///
59    /// Minimum temperature readable by this probe, in 1/10th degrees C
60    ///
61    /// If the value is unknown, the field is set to 0x8000.
62    pub fn minimum_value(&self) -> Option<ProbeTemperature> {
63        self.parts
64            .get_field_word(0x08)
65            .map(|raw| ProbeTemperature::from(raw))
66    }
67
68    /// Resolution
69    ///
70    /// Resolution for the probe’s reading, in 1/1000th degrees C
71    ///
72    /// If the value is unknown, the field is set to 0x8000.
73    pub fn resolution(&self) -> Option<TemperatureProbeResolution> {
74        self.parts
75            .get_field_word(0x0A)
76            .map(|raw| TemperatureProbeResolution::from(raw))
77    }
78
79    /// Tolerance
80    ///
81    /// Tolerance for reading from this probe, in plus/minus 1/10th degrees C
82    ///
83    /// If the value is unknown, the field is set to 0x8000.
84    pub fn tolerance(&self) -> Option<ProbeTemperature> {
85        self.parts
86            .get_field_word(0x0C)
87            .map(|raw| ProbeTemperature::from(raw))
88    }
89
90    /// Accuracy
91    ///
92    /// Accuracy for reading from this probe, in plus/minus 1/100th of a percent
93    ///
94    /// If the value is unknown, the field is set to 0x8000.
95    pub fn accuracy(&self) -> Option<TemperatureProbeAccuracy> {
96        self.parts
97            .get_field_word(0x0E)
98            .map(|raw| TemperatureProbeAccuracy::from(raw))
99    }
100
101    /// OEM defined
102    ///
103    /// OEM- or BIOS vendor-specific information
104    pub fn oem_defined(&self) -> Option<u32> {
105        self.parts.get_field_dword(0x10)
106    }
107
108    /// Nominal value for the probe’s reading in 1/10th degrees C
109    ///
110    /// If the value is unknown, the field is set to 0x8000. This field is
111    /// present in the structure only if the structure’s Length is larger
112    /// than 14h.
113    pub fn nominal_value(&self) -> Option<ProbeTemperature> {
114        self.parts
115            .get_field_word(0x14)
116            .map(|raw| ProbeTemperature::from(raw))
117    }
118}
119
120impl fmt::Debug for SMBiosTemperatureProbe<'_> {
121    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
122        fmt.debug_struct(std::any::type_name::<SMBiosTemperatureProbe<'_>>())
123            .field("header", &self.parts.header)
124            .field("description", &self.description())
125            .field("location_and_status", &self.location_and_status())
126            .field("maximum_value", &self.maximum_value())
127            .field("minimum_value", &self.minimum_value())
128            .field("resolution", &self.resolution())
129            .field("tolerance", &self.tolerance())
130            .field("accuracy", &self.accuracy())
131            .field("oem_defined", &self.oem_defined())
132            .field("nominal_value", &self.nominal_value())
133            .finish()
134    }
135}
136
137impl Serialize for SMBiosTemperatureProbe<'_> {
138    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
139    where
140        S: Serializer,
141    {
142        let mut state = serializer.serialize_struct("SMBiosTemperatureProbe", 10)?;
143        state.serialize_field("header", &self.parts.header)?;
144        state.serialize_field("description", &self.description())?;
145        state.serialize_field("location_and_status", &self.location_and_status())?;
146        state.serialize_field("maximum_value", &self.maximum_value())?;
147        state.serialize_field("minimum_value", &self.minimum_value())?;
148        state.serialize_field("resolution", &self.resolution())?;
149        state.serialize_field("tolerance", &self.tolerance())?;
150        state.serialize_field("accuracy", &self.accuracy())?;
151        state.serialize_field("oem_defined", &self.oem_defined())?;
152        state.serialize_field("nominal_value", &self.nominal_value())?;
153        state.end()
154    }
155}
156
157/// # Temperature Probe Location and Status
158#[derive(PartialEq, Eq)]
159pub struct TemperatureProbeLocationAndStatus {
160    /// Raw value
161    pub raw: u8,
162}
163
164impl From<u8> for TemperatureProbeLocationAndStatus {
165    fn from(raw: u8) -> Self {
166        TemperatureProbeLocationAndStatus { raw }
167    }
168}
169
170impl TemperatureProbeLocationAndStatus {
171    /// Temperature Probe Location
172    pub fn location(&self) -> TemperatureProbeLocation {
173        TemperatureProbeLocation::from(self.raw)
174    }
175
176    /// Temperature Probe Status
177    pub fn status(&self) -> TemperatureProbeStatus {
178        TemperatureProbeStatus::from(self.raw)
179    }
180}
181
182impl fmt::Debug for TemperatureProbeLocationAndStatus {
183    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
184        fmt.debug_struct(std::any::type_name::<TemperatureProbeLocationAndStatus>())
185            .field("raw", &self.raw)
186            .field("location", &self.location())
187            .field("status", &self.status())
188            .finish()
189    }
190}
191
192impl Serialize for TemperatureProbeLocationAndStatus {
193    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
194    where
195        S: Serializer,
196    {
197        let mut state = serializer.serialize_struct("TemperatureProbeLocationAndStatus", 3)?;
198        state.serialize_field("raw", &self.raw)?;
199        state.serialize_field("location", &self.location())?;
200        state.serialize_field("status", &self.status())?;
201        state.end()
202    }
203}
204
205/// # Temperature Probe Status
206#[derive(Serialize, Debug, PartialEq, Eq)]
207pub enum TemperatureProbeStatus {
208    /// Other
209    Other,
210    /// Unknown
211    Unknown,
212    /// OK
213    OK,
214    /// Non-critical
215    NonCritical,
216    /// Critical
217    Critical,
218    /// Non-recoverable
219    NonRecoverable,
220    /// A value unknown to this standard, check the raw value
221    None,
222}
223
224impl From<u8> for TemperatureProbeStatus {
225    fn from(raw: u8) -> Self {
226        match raw & 0b1110_0000 {
227            0b0000_0000 => TemperatureProbeStatus::None,
228            0b0010_0000 => TemperatureProbeStatus::Other,
229            0b0100_0000 => TemperatureProbeStatus::Unknown,
230            0b0110_0000 => TemperatureProbeStatus::OK,
231            0b1000_0000 => TemperatureProbeStatus::NonCritical,
232            0b1010_0000 => TemperatureProbeStatus::Critical,
233            0b1100_0000 => TemperatureProbeStatus::NonRecoverable,
234            0b1110_0000 => TemperatureProbeStatus::None,
235            _ => panic!("impossible value"),
236        }
237    }
238}
239
240/// # Temperature Probe Location
241#[derive(Serialize, Debug, PartialEq, Eq)]
242pub enum TemperatureProbeLocation {
243    /// Other
244    Other,
245    /// Unknown
246    Unknown,
247    /// Processor
248    Processor,
249    /// Disk
250    Disk,
251    /// Peripheral Bay
252    PeripheralBay,
253    /// System Management Moduel
254    SystemManagementModule,
255    /// Motherboard
256    Motherboard,
257    /// Memory Module
258    MemoryModule,
259    /// Processor Module
260    ProcessorModule,
261    /// Power Unit
262    PowerUnit,
263    /// Add-in Card
264    AddInCard,
265    /// Front Panel Board
266    FrontPanelBoard,
267    /// Back Panel Board
268    BackPanelBoard,
269    /// Power System Board
270    PowerSystemBoard,
271    /// Drive Back Plane
272    DriveBackPlane,
273    /// A value unknown to this standard, check the raw value
274    None,
275}
276
277impl From<u8> for TemperatureProbeLocation {
278    fn from(raw: u8) -> Self {
279        match raw & 0b0001_1111 {
280            0b0000_0001 => TemperatureProbeLocation::Other,
281            0b0000_0010 => TemperatureProbeLocation::Unknown,
282            0b0000_0011 => TemperatureProbeLocation::Processor,
283            0b0000_0100 => TemperatureProbeLocation::Disk,
284            0b0000_0101 => TemperatureProbeLocation::PeripheralBay,
285            0b0000_0110 => TemperatureProbeLocation::SystemManagementModule,
286            0b0000_0111 => TemperatureProbeLocation::Motherboard,
287            0b0000_1000 => TemperatureProbeLocation::MemoryModule,
288            0b0000_1001 => TemperatureProbeLocation::ProcessorModule,
289            0b0000_1010 => TemperatureProbeLocation::PowerUnit,
290            0b0000_1011 => TemperatureProbeLocation::AddInCard,
291            0b0000_1100 => TemperatureProbeLocation::FrontPanelBoard,
292            0b0000_1101 => TemperatureProbeLocation::BackPanelBoard,
293            0b0000_1110 => TemperatureProbeLocation::PowerSystemBoard,
294            0b0000_1111 => TemperatureProbeLocation::DriveBackPlane,
295            _ => TemperatureProbeLocation::None,
296        }
297    }
298}
299
300/// # Probe Temperature
301#[derive(Serialize, Debug)]
302pub enum ProbeTemperature {
303    /// Temperature in 1/10 degrees C
304    OneTenthDegreesC(u16),
305    /// Temperature is unknown
306    Unknown,
307}
308
309impl From<u16> for ProbeTemperature {
310    fn from(raw: u16) -> Self {
311        match raw {
312            0x8000 => ProbeTemperature::Unknown,
313            _ => ProbeTemperature::OneTenthDegreesC(raw),
314        }
315    }
316}
317
318/// # Temperature Probe Resolution
319#[derive(Serialize, Debug)]
320pub enum TemperatureProbeResolution {
321    /// Resolution for the probe's reading in 1/1000 degrees C
322    OneOneThousandthDegreesC(u16),
323    /// Resolution is unknown
324    Unknown,
325}
326
327impl From<u16> for TemperatureProbeResolution {
328    fn from(raw: u16) -> Self {
329        match raw {
330            0x8000 => TemperatureProbeResolution::Unknown,
331            _ => TemperatureProbeResolution::OneOneThousandthDegreesC(raw),
332        }
333    }
334}
335
336/// # Temperature Probe Accuracy
337#[derive(Serialize, Debug)]
338pub enum TemperatureProbeAccuracy {
339    /// Accuracy for the probe's reading in 1/100 degrees C
340    OneOneHundredthDegreesC(u16),
341    /// Accuracy is unknown
342    Unknown,
343}
344
345impl From<u16> for TemperatureProbeAccuracy {
346    fn from(raw: u16) -> Self {
347        match raw {
348            0x8000 => TemperatureProbeAccuracy::Unknown,
349            _ => TemperatureProbeAccuracy::OneOneHundredthDegreesC(raw),
350        }
351    }
352}
353
354#[cfg(test)]
355mod tests {
356    use super::*;
357
358    #[test]
359    fn unit_test() {
360        let struct_type28 = vec![
361            0x1C, 0x16, 0x2A, 0x00, 0x01, 0x67, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
362            0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x4C, 0x4D, 0x37, 0x38, 0x41, 0x00,
363            0x00,
364        ];
365
366        let parts = UndefinedStruct::new(&struct_type28);
367        let test_struct = SMBiosTemperatureProbe::new(&parts);
368
369        assert_eq!(test_struct.description().to_string(), "LM78A".to_string());
370        assert_eq!(
371            test_struct.location_and_status(),
372            Some(TemperatureProbeLocationAndStatus::from(103))
373        );
374        match test_struct.maximum_value().unwrap() {
375            ProbeTemperature::OneTenthDegreesC(_) => panic!("expected unknown"),
376            ProbeTemperature::Unknown => (),
377        }
378        match test_struct.minimum_value().unwrap() {
379            ProbeTemperature::OneTenthDegreesC(_) => panic!("expected unknown"),
380            ProbeTemperature::Unknown => (),
381        }
382        match test_struct.resolution().unwrap() {
383            TemperatureProbeResolution::OneOneThousandthDegreesC(_) => panic!("expected unknown"),
384            TemperatureProbeResolution::Unknown => (),
385        }
386        match test_struct.tolerance().unwrap() {
387            ProbeTemperature::OneTenthDegreesC(_) => panic!("expected unknown"),
388            ProbeTemperature::Unknown => (),
389        }
390        match test_struct.accuracy().unwrap() {
391            TemperatureProbeAccuracy::OneOneHundredthDegreesC(_) => panic!("expected unknown"),
392            TemperatureProbeAccuracy::Unknown => (),
393        }
394        assert_eq!(test_struct.oem_defined(), Some(0));
395        match test_struct.nominal_value().unwrap() {
396            ProbeTemperature::OneTenthDegreesC(_) => panic!("expected unknown"),
397            ProbeTemperature::Unknown => (),
398        }
399    }
400}