smbioslib/structs/types/
system_reset.rs

1use crate::{SMBiosStruct, UndefinedStruct};
2use serde::{ser::SerializeStruct, Serialize, Serializer};
3use std::fmt;
4
5/// # System Reset (Type 23)
6///
7/// This structure describes whether Automatic System Reset functions are enabled (Status).
8///
9/// If the system has a watchdog timer and the timer is not reset (Timer Reset) before the Interval elapses,
10/// an automatic system reset occurs. The system re-boots according to the Boot Option. This function may
11/// repeat until the Limit is reached, at which time the system re-boots according to the Boot Option at Limit.
12///
13/// NOTE This structure type was added for version 2.2 of this specification.
14///
15/// Compliant with:
16/// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134)
17/// Document Date: 2020-07-17
18pub struct SMBiosSystemReset<'a> {
19    parts: &'a UndefinedStruct,
20}
21
22impl<'a> SMBiosStruct<'a> for SMBiosSystemReset<'a> {
23    const STRUCT_TYPE: u8 = 23u8;
24
25    fn new(parts: &'a UndefinedStruct) -> Self {
26        Self { parts }
27    }
28
29    fn parts(&self) -> &'a UndefinedStruct {
30        self.parts
31    }
32}
33
34impl<'a> SMBiosSystemReset<'a> {
35    /// Capabilities bit-field
36    ///
37    /// Identifies the system-reset capabilities for the system
38    pub fn capabilities(&self) -> Option<SystemResetCapabilities> {
39        self.parts
40            .get_field_byte(0x04)
41            .map(|raw| SystemResetCapabilities::from(raw))
42    }
43
44    /// Reset count
45    ///
46    /// Number of automatic system resets since the last intentional
47    /// reset
48    pub fn reset_count(&self) -> Option<ResetCount> {
49        self.parts
50            .get_field_word(0x05)
51            .map(|raw| ResetCount::from(raw))
52    }
53
54    /// Reset limit
55    ///
56    /// Number of consecutive times the system reset is attempted
57    pub fn reset_limit(&self) -> Option<ResetLimit> {
58        self.parts
59            .get_field_word(0x07)
60            .map(|raw| ResetLimit::from(raw))
61    }
62
63    /// Timer interval
64    ///
65    /// Number of minutes to use for the watchdog timer
66    ///
67    /// If the timer is not reset within this interval, the system reset
68    /// timeout begins.
69    pub fn timer_interval(&self) -> Option<TimerInterval> {
70        self.parts
71            .get_field_word(0x09)
72            .map(|raw| TimerInterval::from(raw))
73    }
74
75    /// Timeout
76    ///
77    /// Number of minutes before the reboot is initiated
78    ///
79    /// It is used after a system power cycle, system reset (local or
80    /// remote), and automatic system reset.
81    pub fn timeout(&self) -> Option<Timeout> {
82        self.parts
83            .get_field_word(0x0B)
84            .map(|raw| Timeout::from(raw))
85    }
86}
87
88impl fmt::Debug for SMBiosSystemReset<'_> {
89    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
90        fmt.debug_struct(std::any::type_name::<SMBiosSystemReset<'_>>())
91            .field("header", &self.parts.header)
92            .field("capabilities", &self.capabilities())
93            .field("reset_count", &self.reset_count())
94            .field("reset_limit", &self.reset_limit())
95            .field("timer_interval", &self.timer_interval())
96            .field("timeout", &self.timeout())
97            .finish()
98    }
99}
100
101impl Serialize for SMBiosSystemReset<'_> {
102    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
103    where
104        S: Serializer,
105    {
106        let mut state = serializer.serialize_struct("SMBiosSystemReset", 6)?;
107        state.serialize_field("header", &self.parts.header)?;
108        state.serialize_field("capabilities", &self.capabilities())?;
109        state.serialize_field("reset_count", &self.reset_count())?;
110        state.serialize_field("reset_limit", &self.reset_limit())?;
111        state.serialize_field("timer_interval", &self.timer_interval())?;
112        state.serialize_field("timeout", &self.timeout())?;
113        state.end()
114    }
115}
116
117/// # System Reset Capabilities
118#[derive(PartialEq, Eq)]
119pub struct SystemResetCapabilities {
120    /// Raw byte of the system reset capabilities
121    pub raw: u8,
122}
123
124impl From<u8> for SystemResetCapabilities {
125    fn from(raw: u8) -> Self {
126        SystemResetCapabilities { raw }
127    }
128}
129
130impl SystemResetCapabilities {
131    /// System contains a watchdog timer; either
132    /// True (1) or False (0).
133    pub fn has_watchdog_timer(&self) -> bool {
134        self.raw & 0b0010_0000 == 0b0010_0000
135    }
136
137    /// Boot Option on Limit
138    ///
139    /// Identifies one of the system actions
140    /// to be taken when the Reset Limit is reached.
141    pub fn boot_option_on_limit(&self) -> BootOptionOnLimit {
142        BootOptionOnLimit::from(self.raw)
143    }
144
145    /// Boot Option
146    ///
147    /// Indicates one of the following actions
148    /// to be taken after a watchdog reset:
149    pub fn boot_option(&self) -> BootOption {
150        BootOption::from(self.raw)
151    }
152
153    /// Status
154    ///
155    /// Identifies whether (1) or not (0)
156    /// the system reset is enabled by the user.
157    pub fn reset_enabled(&self) -> bool {
158        self.raw & 0b0000_0001 == 0b0000_0001
159    }
160}
161
162impl fmt::Debug for SystemResetCapabilities {
163    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
164        fmt.debug_struct(std::any::type_name::<SystemResetCapabilities>())
165            .field("raw", &self.raw)
166            .field("has_watchdog_timer", &self.has_watchdog_timer())
167            .field("boot_option_on_limit", &self.boot_option_on_limit())
168            .field("boot_option", &self.boot_option())
169            .field("reset_enabled", &self.reset_enabled())
170            .finish()
171    }
172}
173
174impl Serialize for SystemResetCapabilities {
175    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
176    where
177        S: Serializer,
178    {
179        let mut state = serializer.serialize_struct("SystemResetCapabilities", 5)?;
180        state.serialize_field("raw", &self.raw)?;
181        state.serialize_field("has_watchdog_timer", &self.has_watchdog_timer())?;
182        state.serialize_field("boot_option_on_limit", &self.boot_option_on_limit())?;
183        state.serialize_field("boot_option", &self.boot_option())?;
184        state.serialize_field("reset_enabled", &self.reset_enabled())?;
185        state.end()
186    }
187}
188
189/// # Boot Option on Limit
190///
191/// Identifies one of the following system actions to
192/// be taken when the Reset Limit is reached
193#[derive(Serialize, Debug, PartialEq, Eq)]
194pub enum BootOptionOnLimit {
195    /// Reserved, do not use.
196    Reserved,
197    /// Operating System
198    OperatingSystem,
199    /// System utilities
200    SystemUtilities,
201    /// Do not reboot
202    DoNotReboot,
203}
204
205impl From<u8> for BootOptionOnLimit {
206    fn from(raw: u8) -> Self {
207        match raw & 0b0001_1000 {
208            0b0000_0000 => BootOptionOnLimit::Reserved,
209            0b0000_1000 => BootOptionOnLimit::OperatingSystem,
210            0b0001_0000 => BootOptionOnLimit::SystemUtilities,
211            0b0001_1000 => BootOptionOnLimit::DoNotReboot,
212            _ => panic!("impossible value"),
213        }
214    }
215}
216
217/// # Boot Option
218///
219/// Indicates one of the following actions to be taken
220//  after a watchdog reset
221#[derive(Serialize, Debug, PartialEq, Eq)]
222pub enum BootOption {
223    /// Reserved, do not use.
224    Reserved,
225    /// Operating System
226    OperatingSystem,
227    /// System utilities
228    SystemUtilities,
229    /// Do not reboot
230    DoNotReboot,
231}
232
233impl From<u8> for BootOption {
234    fn from(raw: u8) -> Self {
235        match raw & 0b0000_0110 {
236            0b0000_0000 => BootOption::Reserved,
237            0b0000_0010 => BootOption::OperatingSystem,
238            0b0000_0100 => BootOption::SystemUtilities,
239            0b0000_0110 => BootOption::DoNotReboot,
240            _ => panic!("impossible value"),
241        }
242    }
243}
244
245/// # Reset Count
246#[derive(Serialize, Debug)]
247pub enum ResetCount {
248    /// Number of automatic system resets since the last intentional reset
249    Count(u16),
250    /// Reset count is unknown.
251    Unknown,
252}
253
254impl From<u16> for ResetCount {
255    fn from(raw: u16) -> Self {
256        match raw {
257            0xFFFF => ResetCount::Unknown,
258            _ => ResetCount::Count(raw),
259        }
260    }
261}
262
263/// # Reset Limit
264#[derive(Serialize, Debug)]
265pub enum ResetLimit {
266    /// Number of consecutive times the system reset is attempted
267    Count(u16),
268    /// Reset limit is unknown.
269    Unknown,
270}
271
272impl From<u16> for ResetLimit {
273    fn from(raw: u16) -> Self {
274        match raw {
275            0xFFFF => ResetLimit::Unknown,
276            _ => ResetLimit::Count(raw),
277        }
278    }
279}
280
281/// # Timer Interval
282#[derive(Serialize, Debug)]
283pub enum TimerInterval {
284    /// Number of minutes to use for the watchdog timer
285    ///
286    /// If the timer is not reset within this interval,
287    /// the system reset timeout begins.
288    Minutes(u16),
289    /// Timer interval is unknown.
290    Unknown,
291}
292
293impl From<u16> for TimerInterval {
294    fn from(raw: u16) -> Self {
295        match raw {
296            0xFFFF => TimerInterval::Unknown,
297            _ => TimerInterval::Minutes(raw),
298        }
299    }
300}
301
302/// # Timeout
303#[derive(Serialize, Debug)]
304pub enum Timeout {
305    /// Number of minutes before the reboot is initiated
306    ///
307    /// It is used after a system power cycle, system reset
308    // (local or remote), and automatic system reset.
309    Minutes(u16),
310    /// Timeout is unknown.
311    Unknown,
312}
313
314impl From<u16> for Timeout {
315    fn from(raw: u16) -> Self {
316        match raw {
317            0xFFFF => Timeout::Unknown,
318            _ => Timeout::Minutes(raw),
319        }
320    }
321}
322
323#[cfg(test)]
324mod tests {
325    use super::*;
326
327    #[test]
328    fn unit_test() {
329        let struct_type23 = vec![
330            0x17, 0x0D, 0x4F, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
331            0x00,
332        ];
333
334        let parts = UndefinedStruct::new(&struct_type23);
335        let test_struct = SMBiosSystemReset::new(&parts);
336
337        assert_eq!(
338            test_struct.capabilities(),
339            Some(SystemResetCapabilities::from(0))
340        );
341        match test_struct.reset_count().unwrap() {
342            ResetCount::Count(_) => panic!("expected unknown"),
343            ResetCount::Unknown => (),
344        }
345        match test_struct.reset_limit().unwrap() {
346            ResetLimit::Count(_) => panic!("expected unknown"),
347            ResetLimit::Unknown => (),
348        }
349        match test_struct.timer_interval().unwrap() {
350            TimerInterval::Minutes(_) => panic!("expected unknown"),
351            TimerInterval::Unknown => (),
352        }
353        match test_struct.timeout().unwrap() {
354            Timeout::Minutes(_) => panic!("expected unknown"),
355            Timeout::Unknown => (),
356        }
357    }
358}