("other", false) => get_system_information().await.into(),
("power", true) => set_node_power(bmc, query).await,
("power", false) => get_node_power(bmc).await.into(),
- ("reboot", true) => reboot(query).await.into(),
+ ("reboot", true) => reboot(bmc, query).await.into(),
("reload", true) => reload_self().into(),
("reset", true) => reset_node(bmc, query).await.into(),
("sdcard", true) => format_sdcard().into(),
)
}
-async fn reboot(query: Query) -> LegacyResult<()> {
- BmcApplication::reboot(query.contains_key("fel"))
+async fn reboot(bmc: &BmcApplication, query: Query) -> LegacyResult<()> {
+ bmc.reboot(query.contains_key("fel"))
.await
.map_err(Into::into)
}
debug!("node activated bits updated:{:#06b}.", new_state);
let led = new_state != 0;
- if let Err(e) = self.power_controller.power_led(led).await {
- log::warn!("power LED error: {}", e);
- }
+ self.power_controller
+ .power_led(led)
+ .await
+ .unwrap_or_else(|e| log::warn!("power LED error: {:#}", e));
// also update the actual power state accordingly
self.power_controller
.context("error clearing usbboot")
}
- pub async fn reboot(fel: bool) -> anyhow::Result<()> {
+ pub async fn reboot(&self, fel: bool) -> anyhow::Result<()> {
if fel {
peekpoke::write(0x0709_0108, 0x5AA5_A55A);
log::warn!("system reboot into FEL");
}
- tokio::fs::write("/sys/class/leds/fp:reset/brightness", b"1").await?;
+ self.power_controller
+ .status_led(true)
+ .await
+ .unwrap_or_else(|e| log::warn!("status_led: {:#}", e));
+
Command::new("shutdown").args(["-r", "now"]).spawn()?;
Ok(())
}
let bmc = app.clone();
tokio::spawn(async move { bmc.toggle_power_states(false).await });
})
- .add_action(Key::KEY_RESTART, 1, |_| {
- tokio::spawn(BmcApplication::reboot(false));
+ .add_action(Key::KEY_RESTART, 1, |(app, _)| {
+ let bmc = app.clone();
+ tokio::spawn(async move { bmc.reboot(false).await });
})
.run()
.context("event_listener error")
use anyhow::Context;
use gpiod::{Chip, Lines, Output};
use log::{debug, trace};
-use std::time::Duration;
+use std::path::PathBuf;
+use std::{str::FromStr, time::Duration};
use tokio::time::sleep;
+const SYS_LED: &str = "/sys/class/leds/fp::power/brightness";
+const SYS_LED_2_0_5: &str = "/sys/class/leds/fp:sys/brightness";
+const STATUS_LED: &str = "/sys/class/leds/fp::status/brightness";
+const STATUS_LED_2_0_5: &str = "/sys/class/leds/fp:reset/brightness";
const PORT1_EN: &str = "node1-en";
const PORT2_EN: &str = "node2-en";
const PORT3_EN: &str = "node3-en";
// with Linux's power subsystem.
pub struct PowerController {
enable: [Lines<Output>; 4],
+ sysfs_power: PathBuf,
+ sysfs_reset: PathBuf,
}
impl PowerController {
let enable = gpio_output_array!(chip1, port1, port2, port3, port4);
- Ok(PowerController { enable })
+ let sysfs_power = fallback_when_not_exists(SYS_LED, SYS_LED_2_0_5);
+ let sysfs_reset = fallback_when_not_exists(STATUS_LED, STATUS_LED_2_0_5);
+
+ Ok(PowerController {
+ enable,
+ sysfs_power,
+ sysfs_reset,
+ })
}
/// Function to power on/off given nodes. Powering of the nodes is controlled by
}
pub async fn power_led(&self, on: bool) -> anyhow::Result<()> {
- const SYS_LED: &str = "/sys/class/leds/fp:sys/brightness";
- tokio::fs::write(SYS_LED, if on { "1" } else { "0" })
+ tokio::fs::write(&self.sysfs_power, if on { "1" } else { "0" })
.await
.context(SYS_LED)
}
+
+ pub async fn status_led(&self, on: bool) -> anyhow::Result<()> {
+ tokio::fs::write(&self.sysfs_reset, if on { "1" } else { "0" })
+ .await
+ .context(STATUS_LED)
+ }
}
impl std::fmt::Debug for PowerController {
let sys_path = format!("/sys/bus/platform/devices/node{}-power/state", node_id);
tokio::fs::write(sys_path, node_value).await
}
+
+fn fallback_when_not_exists(sysfs: &str, fallback: &str) -> PathBuf {
+ let mut sysfs = PathBuf::from_str(sysfs).expect("valid utf8 path");
+ if !sysfs.exists() {
+ sysfs = PathBuf::from_str(fallback).expect("valid utf8 path");
+ log::info!("power led: falling back to {}", fallback);
+ }
+ sysfs
+}