1use crate::core::{strings::*, Handle, UndefinedStruct};
2use crate::SMBiosStruct;
3use serde::{ser::SerializeStruct, Serialize, Serializer};
4use std::fmt;
5
6pub 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 pub fn temperature_probe_handle(&self) -> Option<Handle> {
35 self.parts.get_field_handle(0x04)
36 }
37
38 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 pub fn cooling_unit_group(&self) -> Option<u8> {
53 self.parts.get_field_byte(0x07)
54 }
55
56 pub fn oem_defined(&self) -> Option<u32> {
58 self.parts.get_field_dword(0x08)
59 }
60
61 pub fn nominal_speed(&self) -> Option<RotationalSpeed> {
68 self.parts
69 .get_field_word(0x0C)
70 .map(|raw| RotationalSpeed::from(raw))
71 }
72
73 pub fn description(&self) -> SMBiosString {
77 self.parts.get_field_string(0x0E)
78 }
79}
80
81#[derive(Serialize, Debug)]
83pub enum RotationalSpeed {
84 Rpm(u16),
86 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#[derive(PartialEq, Eq)]
132pub struct CoolingDeviceTypeAndStatus {
133 pub raw: u8,
140 pub device_status: CoolingDeviceStatus,
142 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#[derive(Serialize, Debug, PartialEq, Eq)]
171pub enum CoolingDeviceStatus {
172 Other,
174 Unknown,
176 OK,
178 NonCritical,
180 Critical,
182 NonRecoverable,
184 None,
186}
187
188#[derive(Serialize, Debug, PartialEq, Eq)]
190pub enum CoolingDeviceType {
191 Other,
193 Unknown,
195 Fan,
197 CentrifugalBlower,
199 ChipFan,
201 CabinetFan,
203 PowerSupplyFan,
205 HeatPipe,
207 IntegratedRefrigeration,
209 ActiveCooling,
211 PassiveCooling,
213 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 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}