1use core::fmt;
9use core::hash::{Hash, Hasher};
10use core::slice::Chunks;
11
12use crate::{HeaderPacked, MalformedStructureError, RawStructure};
13
14#[derive(Clone, Debug, Eq, Hash, PartialEq)]
16pub struct Enclosure<'buffer> {
17 pub handle: u16,
19 pub manufacturer: &'buffer str,
21 pub chassis_lock: bool,
23 pub enclosure_type: EnclosureType,
25 pub version: &'buffer str,
27 pub serial_number: &'buffer str,
29 pub asset_tag_number: &'buffer str,
31 pub boot_up_state: Option<State>,
33 pub power_supply_state: Option<State>,
35 pub thermal_state: Option<State>,
37 pub security_status: Option<SecurityStatus>,
39 pub oem_defined: Option<u32>,
41 pub height: Option<u8>,
45 pub power_cords_number: Option<u8>,
48 pub contained_elements: Option<ContainedElements<'buffer>>,
51 pub sku_number: Option<&'buffer str>,
53}
54
55#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
57pub enum EnclosureType {
58 Other,
59 Unknown,
60 Desktop,
61 LowProfileDesktop,
62 PizzaBox,
63 MiniTower,
64 Tower,
65 Portable,
66 Laptop,
67 Notebook,
68 HandHeld,
69 DockingStation,
70 AllInOne,
71 SubNotebook,
72 SpaceSaving,
73 LunchBox,
74 MainServerChassis,
75 ExpansionChassis,
76 SubChassis,
77 BusExpansionChassis,
78 PeripheralChassis,
79 RaidChassis,
80 RackMountChassis,
81 SealedCasePc,
82 MultiSystemChassis,
90 CompactPci,
91 AdvancedTca,
92 Blade,
96 BladeEnclosure,
100 Tablet,
101 Convertible,
102 Detachable,
103 IotGateway,
104 EmbeddedPc,
105 MiniPc,
106 StickPc,
107 Undefined(u8),
108}
109
110#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
112pub enum State {
113 Other,
114 Unknown,
115 Safe,
116 Warning,
117 Critical,
118 NonRecoverable,
119 Undefined(u8),
120}
121
122#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
124pub enum SecurityStatus {
125 Other,
126 Unknown,
127 None,
128 ExternalInterfaceLockedOut,
129 ExternalInterfaceEnabled,
130 Undefined(u8),
131}
132
133#[derive(Clone, Debug)]
135pub struct ContainedElements<'buffer> {
136 chunks: Chunks<'buffer, u8>,
137 count: u8,
138 record_length: u8,
139}
140
141#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
144pub struct ContainedElement {
145 type_: ContainedElementType,
147 minimum: u8,
151 maximum: u8,
154}
155
156#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
159pub enum ContainedElementType {
160 BoardType(crate::baseboard::BoardType),
161 InfoType(crate::InfoType),
162}
163
164impl<'buffer> Enclosure<'buffer> {
165 pub(crate) fn try_from(structure: RawStructure<'buffer>) -> Result<Enclosure<'buffer>, MalformedStructureError> {
166 #[repr(C)]
167 #[repr(packed)]
168 struct EnclosurePacked2_0 {
169 manufacturer: u8,
170 enclosure_type: u8,
171 version: u8,
172 serial_number: u8,
173 asset_tag_number: u8,
174 }
175
176 const _: () = {
179 assert!(core::mem::size_of::<EnclosurePacked2_0>() + core::mem::size_of::<HeaderPacked>() == 0x09);
180 };
181
182 struct RawEnclosureType(u8);
183 impl RawEnclosureType {
184 fn new(byte: u8) -> Self {
185 RawEnclosureType(byte)
186 }
187 fn get_lock(&self) -> bool {
188 (self.0 & 0b1000_0000) != 0
189 }
190 fn get_type(&self) -> EnclosureType {
191 (self.0 & 0b0111_1111).into()
192 }
193 }
194
195 if structure.data.len() < core::mem::size_of::<EnclosurePacked2_0>() {
196 return Err(crate::MalformedStructureError::InvalidFormattedSectionLength(
197 structure.info,
198 structure.handle,
199 "minimum of ",
200 core::mem::size_of::<EnclosurePacked2_0>() as u8,
201 ));
202 }
203
204 let (minimum, mut extra) = structure.data.split_at(core::mem::size_of::<EnclosurePacked2_0>());
205 let_as_struct!(packed, EnclosurePacked2_0, minimum);
206 let enclosure_type = RawEnclosureType::new(packed.enclosure_type);
207 let mut enclosure = Enclosure {
208 handle: structure.handle,
209 manufacturer: structure.find_string(packed.manufacturer)?,
210 chassis_lock: enclosure_type.get_lock(),
211 enclosure_type: enclosure_type.get_type(),
212 version: structure.find_string(packed.version)?,
213 serial_number: structure.find_string(packed.serial_number)?,
214 asset_tag_number: structure.find_string(packed.asset_tag_number)?,
215 boot_up_state: None,
216 power_supply_state: None,
217 thermal_state: None,
218 security_status: None,
219 oem_defined: None,
220 height: None,
221 power_cords_number: None,
222 contained_elements: None,
223 sku_number: None,
224 };
225 let data = &mut extra;
226
227 let sku_number = read_bytes(data)
229 .and_then(|boot_up_state: u8| {
230 enclosure.boot_up_state = Some(boot_up_state.into());
231 read_bytes(data)
232 })
233 .and_then(|power_supply_state: u8| {
234 enclosure.power_supply_state = Some(power_supply_state.into());
235 read_bytes(data)
236 })
237 .and_then(|thermal_state: u8| {
238 enclosure.thermal_state = Some(thermal_state.into());
239 read_bytes(data)
240 })
241 .and_then(|security_status: u8| {
242 enclosure.security_status = Some(security_status.into());
243 read_bytes(data)
244 })
245 .and_then(|oem_defined: u32| {
247 enclosure.oem_defined = Some(u32::from_le(oem_defined));
248 read_bytes(data)
249 })
250 .and_then(|height: u8| {
251 enclosure.height = Some(height);
252 read_bytes(data)
253 })
254 .and_then(|power_cords_number: u8| {
255 enclosure.power_cords_number = Some(power_cords_number);
256 ContainedElements::new(data)
257 })
258 .and_then(|contained_elements| {
259 enclosure.contained_elements = Some(contained_elements);
260 read_bytes(data)
261 });
262
263 if let Some(sku_number) = sku_number {
265 enclosure.sku_number = Some(structure.find_string(sku_number)?);
266 }
267
268 Ok(enclosure)
269 }
270}
271
272impl From<u8> for EnclosureType {
273 fn from(byte: u8) -> EnclosureType {
274 match byte {
275 0x01 => EnclosureType::Other,
276 0x02 => EnclosureType::Unknown,
277 0x03 => EnclosureType::Desktop,
278 0x04 => EnclosureType::LowProfileDesktop,
279 0x05 => EnclosureType::PizzaBox,
280 0x06 => EnclosureType::MiniTower,
281 0x07 => EnclosureType::Tower,
282 0x08 => EnclosureType::Portable,
283 0x09 => EnclosureType::Laptop,
284 0x0A => EnclosureType::Notebook,
285 0x0B => EnclosureType::HandHeld,
286 0x0C => EnclosureType::DockingStation,
287 0x0D => EnclosureType::AllInOne,
288 0x0E => EnclosureType::SubNotebook,
289 0x0F => EnclosureType::SpaceSaving,
290 0x10 => EnclosureType::LunchBox,
291 0x11 => EnclosureType::MainServerChassis,
292 0x12 => EnclosureType::ExpansionChassis,
293 0x13 => EnclosureType::SubChassis,
294 0x14 => EnclosureType::BusExpansionChassis,
295 0x15 => EnclosureType::PeripheralChassis,
296 0x16 => EnclosureType::RaidChassis,
297 0x17 => EnclosureType::RackMountChassis,
298 0x18 => EnclosureType::SealedCasePc,
299 0x19 => EnclosureType::MultiSystemChassis,
300 0x1A => EnclosureType::CompactPci,
301 0x1B => EnclosureType::AdvancedTca,
302 0x1C => EnclosureType::Blade,
303 0x1D => EnclosureType::BladeEnclosure,
304 0x1E => EnclosureType::Tablet,
305 0x1F => EnclosureType::Convertible,
306 0x20 => EnclosureType::Detachable,
307 0x21 => EnclosureType::IotGateway,
308 0x22 => EnclosureType::EmbeddedPc,
309 0x23 => EnclosureType::MiniPc,
310 0x24 => EnclosureType::StickPc,
311 v => Self::Undefined(v),
312 }
313 }
314}
315impl fmt::Display for EnclosureType {
316 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
317 match self {
318 Self::Other => write!(f, "Other"),
319 Self::Unknown => write!(f, "Unknown"),
320 Self::Desktop => write!(f, "Desktop"),
321 Self::LowProfileDesktop => write!(f, "Low Profile Desktop"),
322 Self::PizzaBox => write!(f, "Pizza Box"),
323 Self::MiniTower => write!(f, "Mini Tower"),
324 Self::Tower => write!(f, "Tower"),
325 Self::Portable => write!(f, "Portable"),
326 Self::Laptop => write!(f, "Laptop"),
327 Self::Notebook => write!(f, "Notebook"),
328 Self::HandHeld => write!(f, "Hand Held"),
329 Self::DockingStation => write!(f, "Docking Station"),
330 Self::AllInOne => write!(f, "All in One"),
331 Self::SubNotebook => write!(f, "Sub Notebook"),
332 Self::SpaceSaving => write!(f, "Space-saving"),
333 Self::LunchBox => write!(f, "Lunch Box"),
334 Self::MainServerChassis => write!(f, "Main Server Chassis"),
335 Self::ExpansionChassis => write!(f, "Expansion Chassis"),
336 Self::SubChassis => write!(f, "SubChassis"),
337 Self::BusExpansionChassis => write!(f, "Bus Expansion Chassis"),
338 Self::PeripheralChassis => write!(f, "Peripheral Chassis"),
339 Self::RaidChassis => write!(f, "RAID Chassis"),
340 Self::RackMountChassis => write!(f, "Rack Mount Chassis"),
341 Self::SealedCasePc => write!(f, "Sealed-case PC"),
342 Self::MultiSystemChassis => write!(f, "Multi-system chassis"),
343 Self::CompactPci => write!(f, "Compact PCI"),
344 Self::AdvancedTca => write!(f, "Advanced TCA"),
345 Self::Blade => write!(f, "Blade"),
346 Self::BladeEnclosure => write!(f, "Blade Enclosure"),
347 Self::Tablet => write!(f, "Tablet"),
348 Self::Convertible => write!(f, "Convertible"),
349 Self::Detachable => write!(f, "Detachable"),
350 Self::IotGateway => write!(f, "IoT Gateway"),
351 Self::EmbeddedPc => write!(f, "Embedded PC"),
352 Self::MiniPc => write!(f, "Mini PC"),
353 Self::StickPc => write!(f, "Stick PC"),
354 Self::Undefined(v) => write!(f, "Undefined: {v}"),
355 }
356 }
357}
358
359impl From<u8> for State {
360 fn from(byte: u8) -> State {
361 match byte {
362 0x01 => Self::Other,
363 0x02 => Self::Unknown,
364 0x03 => Self::Safe,
365 0x04 => Self::Warning,
366 0x05 => Self::Critical,
367 0x06 => Self::NonRecoverable,
368 v => Self::Undefined(v),
369 }
370 }
371}
372impl fmt::Display for State {
373 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
374 match self {
375 Self::Other => write!(f, "Other"),
376 Self::Unknown => write!(f, "Unknown"),
377 Self::Safe => write!(f, "Safe"),
378 Self::Warning => write!(f, "Warning"),
379 Self::Critical => write!(f, "Critical"),
380 Self::NonRecoverable => write!(f, "Non-recoverable"),
381 Self::Undefined(v) => write!(f, "Undefined: {v}"),
382 }
383 }
384}
385
386impl From<u8> for SecurityStatus {
387 fn from(byte: u8) -> SecurityStatus {
388 match byte {
389 0x01 => Self::Other,
390 0x02 => Self::Unknown,
391 0x03 => Self::None,
392 0x04 => Self::ExternalInterfaceLockedOut,
393 0x05 => Self::ExternalInterfaceEnabled,
394 v => Self::Undefined(v),
395 }
396 }
397}
398impl fmt::Display for SecurityStatus {
399 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
400 match self {
401 Self::Other => write!(f, "Other"),
402 Self::Unknown => write!(f, "Unknown"),
403 Self::None => write!(f, "None"),
404 Self::ExternalInterfaceLockedOut => write!(f, "External interface locked out"),
405 Self::ExternalInterfaceEnabled => write!(f, "External interface enabled"),
406 Self::Undefined(v) => write!(f, "Undefined: {v}"),
407 }
408 }
409}
410
411impl<'buffer> ContainedElements<'buffer> {
412 fn new(data: &mut &'buffer [u8]) -> Option<Self> {
413 let count: u8 = read_bytes(data)?;
414 let record_length: u8 = read_bytes(data)?;
415
416 if count == 0 || record_length == 0 {
417 return Some(Self {
418 chunks: [].chunks(usize::MAX),
419 count,
420 record_length,
421 });
422 }
423
424 let length = (count * record_length) as usize;
425 let chunks = data.get(0..length)?.chunks(record_length as usize);
426 *data = &data[length..];
427 Some(Self {
428 chunks,
429 count,
430 record_length,
431 })
432 }
433
434 pub fn count(&self) -> u8 {
435 self.count
436 }
437}
438
439impl PartialEq for ContainedElements<'_> {
440 fn eq(&self, other: &Self) -> bool {
441 self.chunks.clone().eq(other.chunks.clone())
442 && self.count == other.count
443 && self.record_length == other.record_length
444 }
445}
446impl Eq for ContainedElements<'_> {}
447impl Hash for ContainedElements<'_> {
448 fn hash<H: Hasher>(&self, state: &mut H) {
449 self.chunks.clone().for_each(|c| c.hash(state));
450 self.count.hash(state);
451 self.record_length.hash(state);
452 }
453}
454impl Iterator for ContainedElements<'_> {
455 type Item = ContainedElement;
456
457 fn next(&mut self) -> Option<Self::Item> {
458 self.chunks.next().map(|a| a.into())
459 }
460}
461
462impl From<&[u8]> for ContainedElement {
463 fn from(data: &[u8]) -> ContainedElement {
464 #[repr(C)]
465 #[repr(packed)]
466 struct ContainedElement2_3 {
467 type_: u8,
468 minimum: u8,
469 maximum: u8,
470 }
471 let_as_struct!(packed, ContainedElement2_3, data);
472 ContainedElement {
473 type_: packed.type_.into(),
474 minimum: packed.minimum,
475 maximum: packed.maximum,
476 }
477 }
478}
479impl fmt::Display for ContainedElement {
480 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
481 write!(f, "{} ({}-{})", self.type_, self.minimum, self.maximum)
482 }
483}
484
485impl From<u8> for ContainedElementType {
486 fn from(byte: u8) -> ContainedElementType {
487 let val = byte & 0b0111_1111;
488 if byte & 0b1000_0000 == 0 {
489 Self::BoardType(val.into())
490 } else {
491 Self::InfoType(val.into())
492 }
493 }
494}
495impl fmt::Display for ContainedElementType {
496 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
497 match self {
498 Self::BoardType(board) => write!(f, "Baseboard type: {board}"),
499 Self::InfoType(info) => write!(f, "Structure type: {info}"),
500 }
501 }
502}
503
504fn read_bytes<T: Copy>(data: &mut &[u8]) -> Option<T> {
505 if data.len() < core::mem::size_of::<T>() {
506 return None;
507 }
508
509 let value = unsafe { core::ptr::read_unaligned((*data).as_ptr() as *const T) };
510 *data = &data[core::mem::size_of::<T>()..];
511 Some(value)
512}
513
514#[cfg(test)]
515mod tests {
516 use std::prelude::v1::*;
517 #[test]
518 fn enclosure_type() {
519 use super::EnclosureType::*;
520 for i in 1..=0x24 {
521 let (e, s) = match i {
522 0x01 => (Other, "Other".into()),
523 0x09 => (Laptop, "Laptop".into()),
524 0x18 => (SealedCasePc, "Sealed-case PC".into()),
525 0x22 => (EmbeddedPc, "Embedded PC".into()),
526 v @ 0xF0..=0xFF => (Undefined(v), format!("Undefined: {v}")),
527 _ => continue,
528 };
529 assert_eq!(e, i.into(), "{i:#x}");
530 assert_eq!(s, format!("{e}"));
531 }
532 }
533
534 #[test]
535 fn state() {
536 use super::State::*;
537 for i in 0..=0xFF {
538 let (e, s) = match i {
539 0x01 => (Other, "Other".into()),
540 0x04 => (Warning, "Warning".into()),
541 0x06 => (NonRecoverable, "Non-recoverable".into()),
542 v @ 0xF0..=0xFF => (Undefined(v), format!("Undefined: {v}")),
543 _ => continue,
544 };
545 assert_eq!(e, i.into(), "{i:#x}");
546 assert_eq!(s, format!("{e}"));
547 }
548 }
549
550 #[test]
551 fn security_status() {
552 use super::SecurityStatus::*;
553 for i in 0..=0xFF {
554 let (e, s) = match i {
555 0x01 => (Other, "Other".into()),
556 0x03 => (None, "None".into()),
557 0x05 => (ExternalInterfaceEnabled, "External interface enabled".into()),
558 v @ 0xF0..=0xFF => (Undefined(v), format!("Undefined: {v}")),
559 _ => continue,
560 };
561 assert_eq!(e, i.into(), "{i:#x}");
562 assert_eq!(s, format!("{e}"));
563 }
564 }
565
566 #[test]
567 fn contained_element() {
568 use super::{ContainedElement, ContainedElementType};
569 let data = &[
570 (
572 [0b1000_1001, 1, 2],
573 ContainedElement {
574 type_: ContainedElementType::InfoType(crate::InfoType::SystemSlots),
575 minimum: 1,
576 maximum: 2,
577 },
578 "Structure type: System Slots (1-2)",
579 ),
580 (
582 [0b0000_0100, 1, 2],
583 ContainedElement {
584 type_: ContainedElementType::BoardType(crate::baseboard::BoardType::ConnectivitySwitch),
585 minimum: 1,
586 maximum: 2,
587 },
588 "Baseboard type: Connectivity Switch (1-2)",
589 ),
590 ];
591 for (array, contained_element, display) in data {
592 let v = &ContainedElement::from(&array[..]);
593 assert_eq!(contained_element, v);
594 assert_eq!(format!("{display}"), format!("{}", v));
595 }
596 }
597
598 #[test]
599 fn contained_elements() {
600 use super::{ContainedElement, ContainedElementType, ContainedElements};
601 let structure_data = [
602 0x02, 0x03, 0x91, 0x01, 0x02, 0x07, 0x03, 0x04, 0x03, ];
607 let mut data: &[u8] = &structure_data;
608 let mut contained_elements = ContainedElements::new(&mut data).expect("should not be empty");
609 if let Some(el) = contained_elements.next() {
610 assert_eq!(
611 ContainedElement {
612 type_: ContainedElementType::InfoType(crate::InfoType::MemoryDevice),
613 minimum: 1,
614 maximum: 2
615 },
616 el
617 );
618 }
619 if let Some(el) = contained_elements.next() {
620 assert_eq!(
621 ContainedElement {
622 type_: ContainedElementType::BoardType(crate::baseboard::BoardType::IoModule),
623 minimum: 3,
624 maximum: 4
625 },
626 el
627 );
628 }
629 assert_eq!(contained_elements.next(), None);
630 assert_eq!(data, &structure_data[8..]);
632 }
633
634 #[test]
635 fn dmi_bin() {
636 use super::*;
637 const DMIDECODE_BIN: &[u8] = include_bytes!("../../tests/data/dmi.0.bin");
638 let entry_point = crate::EntryPoint::search(DMIDECODE_BIN).unwrap();
639 let enc = entry_point
640 .structures(&DMIDECODE_BIN[(entry_point.smbios_address() as usize)..])
641 .find_map(|s| {
642 if let Ok(crate::Structure::Enclosure(enc)) = s {
643 Some(enc)
644 } else {
645 None
646 }
647 })
648 .unwrap();
649 let sample = Enclosure {
650 handle: 768,
651 manufacturer: "Dell Inc.",
652 chassis_lock: true,
653 enclosure_type: EnclosureType::RackMountChassis,
654 version: "",
655 serial_number: "XXXXXXX",
656 asset_tag_number: "",
657 boot_up_state: Some(State::Safe),
658 power_supply_state: Some(State::Safe),
659 thermal_state: Some(State::Safe),
660 security_status: Some(SecurityStatus::Unknown),
661 oem_defined: Some(0x01010101),
662 height: Some(2),
663 power_cords_number: Some(2),
664 contained_elements: Some(ContainedElements {
665 chunks: [145, 1, 2, 3, 255, 0].chunks(3),
666 count: 2,
667 record_length: 3,
668 }),
669 sku_number: Some("SKU Number"),
670 };
671
672 assert_eq!(sample, enc);
673 assert_eq!(format!("{}", enc.manufacturer), "Dell Inc.", "Manufacturer");
674 assert_eq!(format!("{}", enc.enclosure_type), "Rack Mount Chassis", "Type");
675 assert_eq!(format!("{}", enc.chassis_lock), "true", "Lock");
676 assert_eq!(format!("{}", enc.version), "", "Version");
677 assert_eq!(format!("{}", enc.serial_number), "XXXXXXX", "Serial Number");
678 assert_eq!(format!("{}", enc.asset_tag_number), "", "Asset Tag");
679 assert_eq!(
680 enc.boot_up_state.map(|v| format!("{v}")),
681 Some("Safe".into()),
682 "Boot-up State"
683 );
684 assert_eq!(
685 enc.power_supply_state.map(|v| format!("{v}")),
686 Some("Safe".into()),
687 "Power Supply State"
688 );
689 assert_eq!(
690 enc.thermal_state.map(|v| format!("{v}")),
691 Some("Safe".into()),
692 "Thermal State"
693 );
694 assert_eq!(
695 enc.security_status.map(|v| format!("{v}")),
696 Some("Unknown".into()),
697 "Security Status"
698 );
699 assert_eq!(
700 enc.oem_defined.map(|v| format!("{v:#010X}")),
701 Some("0x01010101".into()),
702 "OEM Information"
703 );
704 assert_eq!(enc.height, Some(2), "Height");
705 assert_eq!(enc.power_cords_number, Some(2), "Number Of Power Cords");
706 assert_eq!(
707 enc.contained_elements
708 .clone()
709 .and_then(|mut ce| ce.next().map(|s| format!("{s}"))),
710 Some("Structure type: Memory Device (1-2)".into()),
711 "Number Of Power Cords"
712 );
713 assert_eq!(
714 enc.contained_elements
715 .clone()
716 .and_then(|mut ce| ce.nth(1).map(|s| format!("{s}"))),
717 Some("Baseboard type: Server Blade (255-0)".into()),
718 "Number Of Power Cords"
719 );
720 assert_eq!(
721 enc.sku_number.map(|v| v.to_string()),
722 Some("SKU Number".into()),
723 "SKU Number"
724 );
725 }
726
727 #[test]
728 fn no_sku_on_3_14() {
729 use super::*;
730
731 let enclosure = Enclosure::try_from(RawStructure {
732 version: crate::SmbiosVersion { major: 3, minor: 14 },
733 info: crate::InfoType::Enclosure,
734 length: 20,
735 handle: 153,
736 data: &[1, 1, 0, 0, 0, 3, 3, 3, 2, 0, 0, 0, 0, 0, 0, 0],
737 strings: &[71, 111, 111, 103, 108, 101, 0, 0],
738 })
739 .expect("failed to create enclosure");
740
741 assert_eq!(
742 enclosure,
743 Enclosure {
744 handle: 153,
745 manufacturer: "Google",
746 chassis_lock: false,
747 enclosure_type: EnclosureType::Other,
748 version: "",
749 serial_number: "",
750 asset_tag_number: "",
751 boot_up_state: Some(State::Safe),
752 power_supply_state: Some(State::Safe),
753 thermal_state: Some(State::Safe),
754 security_status: Some(SecurityStatus::Unknown),
755 oem_defined: Some(0),
756 height: Some(0),
757 power_cords_number: Some(0),
758 contained_elements: None,
759 sku_number: None
760 }
761 )
762 }
763}