use crate::{SMBiosStruct, UndefinedStruct};
use serde::{ser::SerializeStruct, Serialize, Serializer};
use std::fmt;
pub struct SMBiosSystemReset<'a> {
parts: &'a UndefinedStruct,
}
impl<'a> SMBiosStruct<'a> for SMBiosSystemReset<'a> {
const STRUCT_TYPE: u8 = 23u8;
fn new(parts: &'a UndefinedStruct) -> Self {
Self { parts }
}
fn parts(&self) -> &'a UndefinedStruct {
self.parts
}
}
impl<'a> SMBiosSystemReset<'a> {
pub fn capabilities(&self) -> Option<SystemResetCapabilities> {
self.parts
.get_field_byte(0x04)
.map(|raw| SystemResetCapabilities::from(raw))
}
pub fn reset_count(&self) -> Option<ResetCount> {
self.parts
.get_field_word(0x05)
.map(|raw| ResetCount::from(raw))
}
pub fn reset_limit(&self) -> Option<ResetLimit> {
self.parts
.get_field_word(0x07)
.map(|raw| ResetLimit::from(raw))
}
pub fn timer_interval(&self) -> Option<TimerInterval> {
self.parts
.get_field_word(0x09)
.map(|raw| TimerInterval::from(raw))
}
pub fn timeout(&self) -> Option<Timeout> {
self.parts
.get_field_word(0x0B)
.map(|raw| Timeout::from(raw))
}
}
impl fmt::Debug for SMBiosSystemReset<'_> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct(std::any::type_name::<SMBiosSystemReset<'_>>())
.field("header", &self.parts.header)
.field("capabilities", &self.capabilities())
.field("reset_count", &self.reset_count())
.field("reset_limit", &self.reset_limit())
.field("timer_interval", &self.timer_interval())
.field("timeout", &self.timeout())
.finish()
}
}
impl Serialize for SMBiosSystemReset<'_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_struct("SMBiosSystemReset", 6)?;
state.serialize_field("header", &self.parts.header)?;
state.serialize_field("capabilities", &self.capabilities())?;
state.serialize_field("reset_count", &self.reset_count())?;
state.serialize_field("reset_limit", &self.reset_limit())?;
state.serialize_field("timer_interval", &self.timer_interval())?;
state.serialize_field("timeout", &self.timeout())?;
state.end()
}
}
#[derive(PartialEq, Eq)]
pub struct SystemResetCapabilities {
pub raw: u8,
}
impl From<u8> for SystemResetCapabilities {
fn from(raw: u8) -> Self {
SystemResetCapabilities { raw }
}
}
impl SystemResetCapabilities {
pub fn has_watchdog_timer(&self) -> bool {
self.raw & 0b0010_0000 == 0b0010_0000
}
pub fn boot_option_on_limit(&self) -> BootOptionOnLimit {
BootOptionOnLimit::from(self.raw)
}
pub fn boot_option(&self) -> BootOption {
BootOption::from(self.raw)
}
pub fn reset_enabled(&self) -> bool {
self.raw & 0b0000_0001 == 0b0000_0001
}
}
impl fmt::Debug for SystemResetCapabilities {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct(std::any::type_name::<SystemResetCapabilities>())
.field("raw", &self.raw)
.field("has_watchdog_timer", &self.has_watchdog_timer())
.field("boot_option_on_limit", &self.boot_option_on_limit())
.field("boot_option", &self.boot_option())
.field("reset_enabled", &self.reset_enabled())
.finish()
}
}
impl Serialize for SystemResetCapabilities {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_struct("SystemResetCapabilities", 5)?;
state.serialize_field("raw", &self.raw)?;
state.serialize_field("has_watchdog_timer", &self.has_watchdog_timer())?;
state.serialize_field("boot_option_on_limit", &self.boot_option_on_limit())?;
state.serialize_field("boot_option", &self.boot_option())?;
state.serialize_field("reset_enabled", &self.reset_enabled())?;
state.end()
}
}
#[derive(Serialize, Debug, PartialEq, Eq)]
pub enum BootOptionOnLimit {
Reserved,
OperatingSystem,
SystemUtilities,
DoNotReboot,
}
impl From<u8> for BootOptionOnLimit {
fn from(raw: u8) -> Self {
match raw & 0b0001_1000 {
0b0000_0000 => BootOptionOnLimit::Reserved,
0b0000_1000 => BootOptionOnLimit::OperatingSystem,
0b0001_0000 => BootOptionOnLimit::SystemUtilities,
0b0001_1000 => BootOptionOnLimit::DoNotReboot,
_ => panic!("impossible value"),
}
}
}
#[derive(Serialize, Debug, PartialEq, Eq)]
pub enum BootOption {
Reserved,
OperatingSystem,
SystemUtilities,
DoNotReboot,
}
impl From<u8> for BootOption {
fn from(raw: u8) -> Self {
match raw & 0b0000_0110 {
0b0000_0000 => BootOption::Reserved,
0b0000_0010 => BootOption::OperatingSystem,
0b0000_0100 => BootOption::SystemUtilities,
0b0000_0110 => BootOption::DoNotReboot,
_ => panic!("impossible value"),
}
}
}
#[derive(Serialize, Debug)]
pub enum ResetCount {
Count(u16),
Unknown,
}
impl From<u16> for ResetCount {
fn from(raw: u16) -> Self {
match raw {
0xFFFF => ResetCount::Unknown,
_ => ResetCount::Count(raw),
}
}
}
#[derive(Serialize, Debug)]
pub enum ResetLimit {
Count(u16),
Unknown,
}
impl From<u16> for ResetLimit {
fn from(raw: u16) -> Self {
match raw {
0xFFFF => ResetLimit::Unknown,
_ => ResetLimit::Count(raw),
}
}
}
#[derive(Serialize, Debug)]
pub enum TimerInterval {
Minutes(u16),
Unknown,
}
impl From<u16> for TimerInterval {
fn from(raw: u16) -> Self {
match raw {
0xFFFF => TimerInterval::Unknown,
_ => TimerInterval::Minutes(raw),
}
}
}
#[derive(Serialize, Debug)]
pub enum Timeout {
Minutes(u16),
Unknown,
}
impl From<u16> for Timeout {
fn from(raw: u16) -> Self {
match raw {
0xFFFF => Timeout::Unknown,
_ => Timeout::Minutes(raw),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn unit_test() {
let struct_type23 = vec![
0x17, 0x0D, 0x4F, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
0x00,
];
let parts = UndefinedStruct::new(&struct_type23);
let test_struct = SMBiosSystemReset::new(&parts);
assert_eq!(
test_struct.capabilities(),
Some(SystemResetCapabilities::from(0))
);
match test_struct.reset_count().unwrap() {
ResetCount::Count(_) => panic!("expected unknown"),
ResetCount::Unknown => (),
}
match test_struct.reset_limit().unwrap() {
ResetLimit::Count(_) => panic!("expected unknown"),
ResetLimit::Unknown => (),
}
match test_struct.timer_interval().unwrap() {
TimerInterval::Minutes(_) => panic!("expected unknown"),
TimerInterval::Unknown => (),
}
match test_struct.timeout().unwrap() {
Timeout::Minutes(_) => panic!("expected unknown"),
Timeout::Unknown => (),
}
}
}