2023-02-05 14:15:48 +01:00
|
|
|
#[cfg(feature = "serde")]
|
|
|
|
use serde::{Deserialize, Serialize};
|
2023-02-05 01:18:23 +01:00
|
|
|
|
2023-02-05 14:15:48 +01:00
|
|
|
/// Generic trait for a device capable of switching itself on or off.
|
2023-02-05 01:18:23 +01:00
|
|
|
pub trait PowerSwitch {
|
2023-02-05 14:15:48 +01:00
|
|
|
type Error;
|
|
|
|
|
|
|
|
fn switch_on(&mut self) -> Result<(), Self::Error>;
|
|
|
|
fn switch_off(&mut self) -> Result<(), Self::Error>;
|
2023-02-05 01:18:23 +01:00
|
|
|
|
|
|
|
fn is_switch_on(&self) -> bool {
|
|
|
|
self.switch_state() == SwitchState::On
|
|
|
|
}
|
|
|
|
|
|
|
|
fn switch_state(&self) -> SwitchState;
|
|
|
|
}
|
|
|
|
|
2023-02-05 14:15:48 +01:00
|
|
|
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
|
|
|
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
2023-02-05 01:18:23 +01:00
|
|
|
pub enum SwitchState {
|
|
|
|
Off = 0,
|
|
|
|
On = 1,
|
2023-02-05 14:15:48 +01:00
|
|
|
Unknown = 2,
|
2023-02-05 18:59:28 +01:00
|
|
|
Faulty = 3,
|
2023-02-05 01:18:23 +01:00
|
|
|
}
|
|
|
|
|
2024-03-09 15:11:11 +01:00
|
|
|
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
|
|
|
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
|
|
pub enum SwitchStateBinary {
|
|
|
|
Off = 0,
|
|
|
|
On = 1,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TryFrom<SwitchState> for SwitchStateBinary {
|
|
|
|
type Error = ();
|
|
|
|
fn try_from(value: SwitchState) -> Result<Self, Self::Error> {
|
|
|
|
match value {
|
|
|
|
SwitchState::Off => Ok(SwitchStateBinary::Off),
|
|
|
|
SwitchState::On => Ok(SwitchStateBinary::On),
|
|
|
|
_ => Err(()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Into<u64>> From<T> for SwitchStateBinary {
|
|
|
|
fn from(value: T) -> Self {
|
|
|
|
if value.into() == 0 {
|
|
|
|
return SwitchStateBinary::Off;
|
|
|
|
}
|
|
|
|
SwitchStateBinary::On
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<SwitchStateBinary> for SwitchState {
|
|
|
|
fn from(value: SwitchStateBinary) -> Self {
|
|
|
|
match value {
|
|
|
|
SwitchStateBinary::Off => SwitchState::Off,
|
|
|
|
SwitchStateBinary::On => SwitchState::On,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-05 14:15:48 +01:00
|
|
|
pub type SwitchId = u16;
|
|
|
|
|
|
|
|
/// Generic trait for a device capable of turning on and off switches.
|
2023-02-13 09:20:00 +01:00
|
|
|
pub trait PowerSwitcherCommandSender {
|
2023-02-05 14:15:48 +01:00
|
|
|
type Error;
|
2023-02-05 01:18:23 +01:00
|
|
|
|
2023-02-05 14:15:48 +01:00
|
|
|
fn send_switch_on_cmd(&mut self, switch_id: SwitchId) -> Result<(), Self::Error>;
|
|
|
|
fn send_switch_off_cmd(&mut self, switch_id: SwitchId) -> Result<(), Self::Error>;
|
2023-02-13 09:20:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
pub trait PowerSwitchInfo {
|
|
|
|
type Error;
|
|
|
|
|
2023-02-05 14:15:48 +01:00
|
|
|
/// Retrieve the switch state
|
2023-02-07 14:56:50 +01:00
|
|
|
fn get_switch_state(&mut self, switch_id: SwitchId) -> Result<SwitchState, Self::Error>;
|
2023-02-05 14:15:48 +01:00
|
|
|
|
2023-02-07 16:01:25 +01:00
|
|
|
fn get_is_switch_on(&mut self, switch_id: SwitchId) -> Result<bool, Self::Error> {
|
|
|
|
Ok(self.get_switch_state(switch_id)? == SwitchState::On)
|
2023-02-05 14:15:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// The maximum delay it will take to change a switch.
|
|
|
|
///
|
|
|
|
/// This may take into account the time to send a command, wait for it to be executed, and
|
|
|
|
/// see the switch changed.
|
|
|
|
fn switch_delay_ms(&self) -> u32;
|
2023-02-05 18:59:28 +01:00
|
|
|
}
|
2023-02-06 11:38:13 +01:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2023-02-27 17:00:21 +01:00
|
|
|
#![allow(dead_code)]
|
2023-02-06 11:38:13 +01:00
|
|
|
use super::*;
|
2023-02-14 15:53:14 +01:00
|
|
|
use std::boxed::Box;
|
2023-02-06 11:38:13 +01:00
|
|
|
|
|
|
|
struct Pcdu {
|
2023-02-14 15:53:14 +01:00
|
|
|
switch_rx: std::sync::mpsc::Receiver<(SwitchId, u16)>,
|
2023-02-06 11:38:13 +01:00
|
|
|
}
|
2023-02-27 17:00:21 +01:00
|
|
|
|
|
|
|
#[derive(Eq, PartialEq)]
|
2023-02-06 11:38:13 +01:00
|
|
|
enum DeviceState {
|
|
|
|
OFF,
|
|
|
|
SwitchingPower,
|
|
|
|
ON,
|
|
|
|
SETUP,
|
2023-02-14 15:53:14 +01:00
|
|
|
IDLE,
|
2023-02-06 11:38:13 +01:00
|
|
|
}
|
|
|
|
struct MyComplexDevice {
|
2023-02-14 15:53:14 +01:00
|
|
|
power_switcher: Box<dyn PowerSwitcherCommandSender<Error = ()>>,
|
2023-02-27 17:00:21 +01:00
|
|
|
power_info: Box<dyn PowerSwitchInfo<Error = ()>>,
|
2023-02-06 11:38:13 +01:00
|
|
|
switch_id: SwitchId,
|
|
|
|
some_state: u16,
|
|
|
|
dev_state: DeviceState,
|
|
|
|
mode: u32,
|
|
|
|
submode: u16,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl MyComplexDevice {
|
|
|
|
pub fn periodic_op(&mut self) {
|
|
|
|
// .. mode command coming in
|
|
|
|
let mode = 1;
|
|
|
|
if mode == 1 {
|
|
|
|
if self.dev_state == DeviceState::OFF {
|
2023-02-14 15:53:14 +01:00
|
|
|
self.power_switcher
|
|
|
|
.send_switch_on_cmd(self.switch_id)
|
|
|
|
.expect("sending siwthc cmd failed");
|
2023-02-06 11:38:13 +01:00
|
|
|
self.dev_state = DeviceState::SwitchingPower;
|
|
|
|
}
|
|
|
|
if self.dev_state == DeviceState::SwitchingPower {
|
2023-02-27 17:00:21 +01:00
|
|
|
if self.power_info.get_is_switch_on(0).unwrap() {
|
2023-02-06 11:38:13 +01:00
|
|
|
self.dev_state = DeviceState::ON;
|
|
|
|
self.mode = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-02-14 15:53:14 +01:00
|
|
|
}
|