Skip to main content

smbioslib/structs/types/
cooling_device.rs

1use crate::core::{strings::*, Handle, UndefinedStruct};
2use crate::SMBiosStruct;
3use serde::{ser::SerializeStruct, Serialize, Serializer};
4use std::fmt;
5
6/// # Cooling Device (Type 27)
7///
8/// This structure describes the attributes for a cooling device in the system. Each structure describes a single cooling device.
9///
10/// Compliant with:
11/// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134)
12/// Document Date: 2020-07-17
13pub struct SMBiosCoolingDevice<'a> {
14    parts: &'a UndefinedStruct,
15}
16
17impl<'a> SMBiosStruct<'a> for SMBiosCoolingDevice<'a> {
18    const STRUCT_TYPE: u8 = 27u8;
19
20    fn new(parts: &'a UndefinedStruct) -> Self {
21        Self { parts }
22    }
23
24    fn parts(&self) -> &'a UndefinedStruct {
25        self.parts
26    }
27}
28
29impl<'a> SMBiosCoolingDevice<'a> {
30    /// Handle, or instance number, of the temperature
31    /// probe monitoring this cooling device.
32    /// A value of 0xFFFF indicates that no probe is
33    /// provided.
34    pub fn temperature_probe_handle(&self) -> Option<Handle> {
35        self.parts.get_field_handle(0x04)
36    }
37
38    /// Cooling device type and status.
39    pub fn device_type_and_status(&self) -> Option<CoolingDeviceTypeAndStatus> {
40        self.parts
41            .get_field_byte(0x06)
42            .map(|raw| CoolingDeviceTypeAndStatus::from(raw))
43    }
44
45    /// Cooling unit group to which this cooling device is associated
46    /// Having multiple cooling devices in the same
47    /// cooling unit implies a redundant configuration. The
48    /// value is 00h if the cooling device is not a member
49    /// of a redundant cooling unit. Non-zero values imply
50    /// redundancy and that at least one other cooling
51    /// device will be enumerated with the same value
52    pub fn cooling_unit_group(&self) -> Option<u8> {
53        self.parts.get_field_byte(0x07)
54    }
55
56    /// OEM or BIOS vendor-specific information.
57    pub fn oem_defined(&self) -> Option<u32> {
58        self.parts.get_field_dword(0x08)
59    }
60
61    /// Nominal value for the cooling device’s rotational
62    /// speed, in revolutions-per-minute (rpm)
63    /// If the value is unknown or the cooling device is
64    /// non-rotating, the field is set to 0x8000. This field is
65    /// present in the structure only if the structure’s
66    /// length is larger than 0Ch
67    pub fn nominal_speed(&self) -> Option<RotationalSpeed> {
68        self.parts
69            .get_field_word(0x0C)
70            .map(|raw| RotationalSpeed::from(raw))
71    }
72
73    /// Additional descriptive information about the cooling device or its location
74    /// This field is present in the structure only if the
75    /// structure’s length is 0Fh or larger.
76    pub fn description(&self) -> SMBiosString {
77        self.parts.get_field_string(0x0E)
78    }
79}
80
81/// # Rotational Speed
82#[derive(Serialize, Debug)]
83pub enum RotationalSpeed {
84    /// Revolutions per minute (RPM)
85    Rpm(u16),
86    /// RPM is unknown
87    Unknown,
88}
89
90impl From<u16> for RotationalSpeed {
91    fn from(raw: u16) -> Self {
92        match raw {
93            0x8000 => RotationalSpeed::Unknown,
94            _ => RotationalSpeed::Rpm(raw),
95        }
96    }
97}
98
99impl fmt::Debug for SMBiosCoolingDevice<'_> {
100    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
101        fmt.debug_struct(std::any::type_name::<SMBiosCoolingDevice<'_>>())
102            .field("header", &self.parts.header)
103            .field("temperature_probe_handle", &self.temperature_probe_handle())
104            .field("device_type_and_status", &self.device_type_and_status())
105            .field("cooling_unit_group", &self.cooling_unit_group())
106            .field("oem_defined", &self.oem_defined())
107            .field("nominal_speed", &self.nominal_speed())
108            .field("description", &self.description())
109            .finish()
110    }
111}
112
113impl Serialize for SMBiosCoolingDevice<'_> {
114    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
115    where
116        S: Serializer,
117    {
118        let mut state = serializer.serialize_struct("SMBiosCoolingDevice", 7)?;
119        state.serialize_field("header", &self.parts.header)?;
120        state.serialize_field("temperature_probe_handle", &self.temperature_probe_handle())?;
121        state.serialize_field("device_type_and_status", &self.device_type_and_status())?;
122        state.serialize_field("cooling_unit_group", &self.cooling_unit_group())?;
123        state.serialize_field("oem_defined", &self.oem_defined())?;
124        state.serialize_field("nominal_speed", &self.nominal_speed())?;
125        state.serialize_field("description", &self.description())?;
126        state.end()
127    }
128}
129
130/// # Cooling Device Type and Status
131#[derive(PartialEq, Eq)]
132pub struct CoolingDeviceTypeAndStatus {
133    /// Raw value
134    ///
135    /// _raw_ is most useful when _value_ is None.
136    /// This is most likely to occur when the standard was updated but
137    /// this library code has not been updated to match the current
138    /// standard.
139    pub raw: u8,
140    /// The [CoolingDeviceStatus]
141    pub device_status: CoolingDeviceStatus,
142    /// The [CoolingDeviceType]
143    pub device_type: CoolingDeviceType,
144}
145
146impl fmt::Debug for CoolingDeviceTypeAndStatus {
147    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
148        fmt.debug_struct(std::any::type_name::<CoolingDeviceTypeAndStatus>())
149            .field("raw", &self.raw)
150            .field("device_status", &self.device_status)
151            .field("device_type", &self.device_type)
152            .finish()
153    }
154}
155
156impl Serialize for CoolingDeviceTypeAndStatus {
157    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
158    where
159        S: Serializer,
160    {
161        let mut state = serializer.serialize_struct("CoolingDeviceTypeAndStatus", 3)?;
162        state.serialize_field("raw", &self.raw)?;
163        state.serialize_field("device_status", &self.device_status)?;
164        state.serialize_field("device_type", &self.device_type)?;
165        state.end()
166    }
167}
168
169/// # Cooling Device Status
170#[derive(Serialize, Debug, PartialEq, Eq)]
171pub enum CoolingDeviceStatus {
172    /// Other
173    Other,
174    /// Unknown
175    Unknown,
176    /// OK
177    OK,
178    /// Non-critical
179    NonCritical,
180    /// Critical
181    Critical,
182    /// Non-recoverable
183    NonRecoverable,
184    /// A value unknown to this standard, check the raw value
185    None,
186}
187
188/// # Cooling Device Type
189#[derive(Serialize, Debug, PartialEq, Eq)]
190pub enum CoolingDeviceType {
191    /// Other
192    Other,
193    /// Unknown
194    Unknown,
195    /// Fan
196    Fan,
197    /// Centrifugal Blower
198    CentrifugalBlower,
199    /// Chip Fan
200    ChipFan,
201    /// Cabinet Fan
202    CabinetFan,
203    /// Power Supply Fan
204    PowerSupplyFan,
205    /// Heat Pipe
206    HeatPipe,
207    /// Integrated Refrigeration
208    IntegratedRefrigeration,
209    /// Active Cooling
210    ActiveCooling,
211    /// Passive Cooling
212    PassiveCooling,
213    /// A value unknown to this standard, check the raw value
214    None,
215}
216
217impl From<u8> for CoolingDeviceTypeAndStatus {
218    fn from(raw: u8) -> Self {
219        CoolingDeviceTypeAndStatus {
220            device_status: match raw & 0b111_00000 {
221                0b001_00000 => CoolingDeviceStatus::Other,
222                0b010_00000 => CoolingDeviceStatus::Unknown,
223                0b011_00000 => CoolingDeviceStatus::OK,
224                0b100_00000 => CoolingDeviceStatus::NonCritical,
225                0b101_00000 => CoolingDeviceStatus::Critical,
226                0b110_00000 => CoolingDeviceStatus::NonRecoverable,
227                _ => CoolingDeviceStatus::None,
228            },
229            device_type: match raw & 0b000_11111 {
230                0b000_00001 => CoolingDeviceType::Other,
231                0b000_00010 => CoolingDeviceType::Unknown,
232                0b000_00011 => CoolingDeviceType::Fan,
233                0b000_00100 => CoolingDeviceType::CentrifugalBlower,
234                0b000_00101 => CoolingDeviceType::ChipFan,
235                0b000_00110 => CoolingDeviceType::CabinetFan,
236                0b000_00111 => CoolingDeviceType::PowerSupplyFan,
237                0b000_01000 => CoolingDeviceType::HeatPipe,
238                0b000_01001 => CoolingDeviceType::IntegratedRefrigeration,
239                0b000_10000 => CoolingDeviceType::ActiveCooling,
240                0b000_10001 => CoolingDeviceType::PassiveCooling,
241                _ => CoolingDeviceType::None,
242            },
243            raw,
244        }
245    }
246}
247
248#[cfg(test)]
249mod tests {
250    use super::*;
251
252    #[test]
253    fn unit_test() {
254        let struct_type27 = vec![
255            0x1B, 0x0F, 0x2D, 0x00, 0x2A, 0x00, 0x67, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
256            0x01, 0x43, 0x6F, 0x6F, 0x6C, 0x69, 0x6E, 0x67, 0x20, 0x44, 0x65, 0x76, 0x20, 0x31,
257            0x00, 0x00,
258        ];
259
260        let parts = UndefinedStruct::new(&struct_type27);
261        let test_struct = SMBiosCoolingDevice::new(&parts);
262
263        //assert_eq!(test_struct.temperature_probe_handle(), Some(Handle(42)));
264
265        let device_type_and_status = test_struct.device_type_and_status().unwrap();
266        assert_eq!(
267            device_type_and_status.device_status,
268            CoolingDeviceStatus::OK
269        );
270        assert_eq!(
271            device_type_and_status.device_type,
272            CoolingDeviceType::PowerSupplyFan
273        );
274        assert_eq!(test_struct.cooling_unit_group(), Some(1));
275        assert_eq!(test_struct.oem_defined(), Some(0));
276        match test_struct.nominal_speed().unwrap() {
277            RotationalSpeed::Rpm(_) => panic!("expected unknown"),
278            RotationalSpeed::Unknown => (),
279        }
280        assert_eq!(
281            test_struct.description().to_string(),
282            "Cooling Dev 1".to_string()
283        );
284    }
285}