mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-06-14 11:42:02 +08:00
feat: 初步增加 Windows 支持
This commit is contained in:
@@ -11,20 +11,14 @@ use super::led::LedSensor;
|
||||
use super::types::{AtxAction, AtxKeyConfig, AtxLedConfig, AtxState, PowerStatus};
|
||||
use crate::error::{AppError, Result};
|
||||
|
||||
/// ATX power control configuration
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct AtxControllerConfig {
|
||||
/// Whether ATX is enabled
|
||||
pub enabled: bool,
|
||||
/// Power button configuration (used for both short and long press)
|
||||
pub power: AtxKeyConfig,
|
||||
/// Reset button configuration
|
||||
pub reset: AtxKeyConfig,
|
||||
/// LED sensing configuration
|
||||
pub led: AtxLedConfig,
|
||||
}
|
||||
|
||||
/// Internal state holding all ATX components
|
||||
/// Grouped together to reduce lock acquisitions
|
||||
struct AtxInner {
|
||||
config: AtxControllerConfig,
|
||||
@@ -33,12 +27,9 @@ struct AtxInner {
|
||||
led_sensor: Option<LedSensor>,
|
||||
}
|
||||
|
||||
/// ATX Controller
|
||||
///
|
||||
/// Manages ATX power control through independent executors for each action.
|
||||
/// Supports hot-reload of configuration.
|
||||
pub struct AtxController {
|
||||
/// Single lock for all internal state to reduce lock contention
|
||||
inner: RwLock<AtxInner>,
|
||||
}
|
||||
|
||||
@@ -53,6 +44,24 @@ impl AtxController {
|
||||
&& power.baud_rate == reset.baud_rate
|
||||
}
|
||||
|
||||
async fn init_key_executor(
|
||||
warn_label: &str,
|
||||
info_label: &str,
|
||||
config: AtxKeyConfig,
|
||||
mut executor: AtxKeyExecutor,
|
||||
) -> Option<AtxKeyExecutor> {
|
||||
if let Err(e) = executor.init().await {
|
||||
warn!("Failed to initialize {} executor: {}", warn_label, e);
|
||||
return None;
|
||||
}
|
||||
|
||||
info!(
|
||||
"{} executor initialized: {:?} on {} pin {}",
|
||||
info_label, config.driver, config.device, config.pin
|
||||
);
|
||||
Some(executor)
|
||||
}
|
||||
|
||||
async fn init_components(inner: &mut AtxInner) {
|
||||
if Self::should_share_serial_device(&inner.config.power, &inner.config.reset) {
|
||||
match AtxKeyExecutor::open_shared_serial(
|
||||
@@ -60,36 +69,28 @@ impl AtxController {
|
||||
inner.config.power.baud_rate,
|
||||
) {
|
||||
Ok(shared_serial) => {
|
||||
let mut power_executor = AtxKeyExecutor::new_with_shared_serial(
|
||||
inner.config.power.clone(),
|
||||
shared_serial.clone(),
|
||||
);
|
||||
if let Err(e) = power_executor.init().await {
|
||||
warn!("Failed to initialize power executor: {}", e);
|
||||
} else {
|
||||
info!(
|
||||
"Power executor initialized: {:?} on {} pin {}",
|
||||
inner.config.power.driver,
|
||||
inner.config.power.device,
|
||||
inner.config.power.pin
|
||||
for (slot, warn_label, info_label, config, serial) in [
|
||||
(
|
||||
&mut inner.power_executor,
|
||||
"power",
|
||||
"Power",
|
||||
inner.config.power.clone(),
|
||||
shared_serial.clone(),
|
||||
),
|
||||
(
|
||||
&mut inner.reset_executor,
|
||||
"reset",
|
||||
"Reset",
|
||||
inner.config.reset.clone(),
|
||||
shared_serial,
|
||||
),
|
||||
] {
|
||||
let executor = AtxKeyExecutor::new_with_shared_serial(
|
||||
config.clone(),
|
||||
serial,
|
||||
);
|
||||
inner.power_executor = Some(power_executor);
|
||||
}
|
||||
|
||||
let mut reset_executor = AtxKeyExecutor::new_with_shared_serial(
|
||||
inner.config.reset.clone(),
|
||||
shared_serial,
|
||||
);
|
||||
if let Err(e) = reset_executor.init().await {
|
||||
warn!("Failed to initialize reset executor: {}", e);
|
||||
} else {
|
||||
info!(
|
||||
"Reset executor initialized: {:?} on {} pin {}",
|
||||
inner.config.reset.driver,
|
||||
inner.config.reset.device,
|
||||
inner.config.reset.pin
|
||||
);
|
||||
inner.reset_executor = Some(reset_executor);
|
||||
*slot = Self::init_key_executor(warn_label, info_label, config, executor)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
@@ -100,40 +101,18 @@ impl AtxController {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Initialize power executor
|
||||
if inner.config.power.is_configured() {
|
||||
let mut executor = AtxKeyExecutor::new(inner.config.power.clone());
|
||||
if let Err(e) = executor.init().await {
|
||||
warn!("Failed to initialize power executor: {}", e);
|
||||
} else {
|
||||
info!(
|
||||
"Power executor initialized: {:?} on {} pin {}",
|
||||
inner.config.power.driver,
|
||||
inner.config.power.device,
|
||||
inner.config.power.pin
|
||||
);
|
||||
inner.power_executor = Some(executor);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize reset executor
|
||||
if inner.config.reset.is_configured() {
|
||||
let mut executor = AtxKeyExecutor::new(inner.config.reset.clone());
|
||||
if let Err(e) = executor.init().await {
|
||||
warn!("Failed to initialize reset executor: {}", e);
|
||||
} else {
|
||||
info!(
|
||||
"Reset executor initialized: {:?} on {} pin {}",
|
||||
inner.config.reset.driver,
|
||||
inner.config.reset.device,
|
||||
inner.config.reset.pin
|
||||
);
|
||||
inner.reset_executor = Some(executor);
|
||||
for (slot, warn_label, info_label, config) in [
|
||||
(&mut inner.power_executor, "power", "Power", inner.config.power.clone()),
|
||||
(&mut inner.reset_executor, "reset", "Reset", inner.config.reset.clone()),
|
||||
] {
|
||||
if config.is_configured() {
|
||||
let executor = AtxKeyExecutor::new(config.clone());
|
||||
*slot = Self::init_key_executor(warn_label, info_label, config, executor)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize LED sensor
|
||||
if inner.config.led.is_configured() {
|
||||
let mut sensor = LedSensor::new(inner.config.led.clone());
|
||||
if let Err(e) = sensor.init().await {
|
||||
@@ -149,19 +128,17 @@ impl AtxController {
|
||||
}
|
||||
|
||||
async fn shutdown_components(inner: &mut AtxInner) {
|
||||
if let Some(executor) = inner.power_executor.as_mut() {
|
||||
if let Err(e) = executor.shutdown().await {
|
||||
warn!("Failed to shutdown power executor: {}", e);
|
||||
for (slot, label) in [
|
||||
(&mut inner.power_executor, "power"),
|
||||
(&mut inner.reset_executor, "reset"),
|
||||
] {
|
||||
if let Some(executor) = slot.as_mut() {
|
||||
if let Err(e) = executor.shutdown().await {
|
||||
warn!("Failed to shutdown {} executor: {}", label, e);
|
||||
}
|
||||
}
|
||||
*slot = None;
|
||||
}
|
||||
inner.power_executor = None;
|
||||
|
||||
if let Some(executor) = inner.reset_executor.as_mut() {
|
||||
if let Err(e) = executor.shutdown().await {
|
||||
warn!("Failed to shutdown reset executor: {}", e);
|
||||
}
|
||||
}
|
||||
inner.reset_executor = None;
|
||||
|
||||
if let Some(sensor) = inner.led_sensor.as_mut() {
|
||||
if let Err(e) = sensor.shutdown().await {
|
||||
@@ -171,7 +148,20 @@ impl AtxController {
|
||||
inner.led_sensor = None;
|
||||
}
|
||||
|
||||
/// Create a new ATX controller with the specified configuration
|
||||
async fn read_power_status(sensor: Option<&LedSensor>) -> PowerStatus {
|
||||
let Some(sensor) = sensor else {
|
||||
return PowerStatus::Unknown;
|
||||
};
|
||||
|
||||
match sensor.read().await {
|
||||
Ok(status) => status,
|
||||
Err(e) => {
|
||||
debug!("Failed to read ATX LED sensor: {}", e);
|
||||
PowerStatus::Unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(config: AtxControllerConfig) -> Self {
|
||||
Self {
|
||||
inner: RwLock::new(AtxInner {
|
||||
@@ -183,12 +173,10 @@ impl AtxController {
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a disabled ATX controller
|
||||
pub fn disabled() -> Self {
|
||||
Self::new(AtxControllerConfig::default())
|
||||
}
|
||||
|
||||
/// Initialize the ATX controller and its executors
|
||||
pub async fn init(&self) -> Result<()> {
|
||||
let mut inner = self.inner.write().await;
|
||||
|
||||
@@ -204,7 +192,6 @@ impl AtxController {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Reload ATX controller configuration
|
||||
pub async fn reload(&self, config: AtxControllerConfig) -> Result<()> {
|
||||
let mut inner = self.inner.write().await;
|
||||
|
||||
@@ -225,7 +212,6 @@ impl AtxController {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Shutdown ATX controller and release all resources
|
||||
pub async fn shutdown(&self) -> Result<()> {
|
||||
let mut inner = self.inner.write().await;
|
||||
Self::shutdown_components(&mut inner).await;
|
||||
@@ -233,86 +219,48 @@ impl AtxController {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Trigger a power action (short/long/reset)
|
||||
pub async fn trigger_power_action(&self, action: AtxAction) -> Result<()> {
|
||||
let inner = self.inner.read().await;
|
||||
|
||||
match action {
|
||||
AtxAction::Short | AtxAction::Long => {
|
||||
if let Some(executor) = &inner.power_executor {
|
||||
let duration = match action {
|
||||
AtxAction::Short => timing::SHORT_PRESS,
|
||||
AtxAction::Long => timing::LONG_PRESS,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
executor.pulse(duration).await?;
|
||||
} else {
|
||||
return Err(AppError::Config(
|
||||
"Power button not configured for ATX controller".to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
AtxAction::Reset => {
|
||||
if let Some(executor) = &inner.reset_executor {
|
||||
executor.pulse(timing::RESET_PRESS).await?;
|
||||
} else {
|
||||
return Err(AppError::Config(
|
||||
"Reset button not configured for ATX controller".to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
let (executor, duration) = match action {
|
||||
AtxAction::Short => (inner.power_executor.as_ref(), timing::SHORT_PRESS),
|
||||
AtxAction::Long => (inner.power_executor.as_ref(), timing::LONG_PRESS),
|
||||
AtxAction::Reset => (inner.reset_executor.as_ref(), timing::RESET_PRESS),
|
||||
};
|
||||
|
||||
let Some(executor) = executor else {
|
||||
return Err(AppError::Config(match action {
|
||||
AtxAction::Reset => "Reset button not configured for ATX controller",
|
||||
_ => "Power button not configured for ATX controller",
|
||||
}
|
||||
.to_string()));
|
||||
};
|
||||
|
||||
executor.pulse(duration).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Trigger a short power button press
|
||||
pub async fn power_short(&self) -> Result<()> {
|
||||
self.trigger_power_action(AtxAction::Short).await
|
||||
}
|
||||
|
||||
/// Trigger a long power button press
|
||||
pub async fn power_long(&self) -> Result<()> {
|
||||
self.trigger_power_action(AtxAction::Long).await
|
||||
}
|
||||
|
||||
/// Trigger a reset button press
|
||||
pub async fn reset(&self) -> Result<()> {
|
||||
self.trigger_power_action(AtxAction::Reset).await
|
||||
}
|
||||
|
||||
/// Get the current power status using the LED sensor (if configured)
|
||||
pub async fn power_status(&self) -> PowerStatus {
|
||||
let inner = self.inner.read().await;
|
||||
|
||||
if let Some(sensor) = &inner.led_sensor {
|
||||
match sensor.read().await {
|
||||
Ok(status) => status,
|
||||
Err(e) => {
|
||||
debug!("Failed to read ATX LED sensor: {}", e);
|
||||
PowerStatus::Unknown
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PowerStatus::Unknown
|
||||
}
|
||||
Self::read_power_status(inner.led_sensor.as_ref()).await
|
||||
}
|
||||
|
||||
/// Get a snapshot of the ATX state for API responses
|
||||
pub async fn state(&self) -> AtxState {
|
||||
let inner = self.inner.read().await;
|
||||
|
||||
let power_status = if let Some(sensor) = &inner.led_sensor {
|
||||
match sensor.read().await {
|
||||
Ok(status) => status,
|
||||
Err(e) => {
|
||||
debug!("Failed to read ATX LED sensor: {}", e);
|
||||
PowerStatus::Unknown
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PowerStatus::Unknown
|
||||
};
|
||||
let power_status = Self::read_power_status(inner.led_sensor.as_ref()).await;
|
||||
|
||||
AtxState {
|
||||
available: inner.config.enabled,
|
||||
|
||||
Reference in New Issue
Block a user