1use std::time::{Duration, Instant};
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub enum DelayDoState {
26 Init,
27 Disable,
28 MaybeStandby,
29 Idle,
30 Standby,
31 MaybeWait,
32 Active,
33 Waiting,
34 Action,
35}
36
37impl std::fmt::Display for DelayDoState {
38 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39 match self {
40 DelayDoState::Init => write!(f, "init"),
41 DelayDoState::Disable => write!(f, "disable"),
42 DelayDoState::MaybeStandby => write!(f, "maybeStandby"),
43 DelayDoState::Idle => write!(f, "idle"),
44 DelayDoState::Standby => write!(f, "standby"),
45 DelayDoState::MaybeWait => write!(f, "maybeWait"),
46 DelayDoState::Active => write!(f, "active"),
47 DelayDoState::Waiting => write!(f, "waiting"),
48 DelayDoState::Action => write!(f, "action"),
49 }
50 }
51}
52
53#[derive(Debug, Clone, Copy)]
55pub struct DelayDoInputs {
56 pub enable: bool,
58 pub enable_changed: bool,
60 pub standby: bool,
62 pub standby_changed: bool,
64 pub active: bool,
66 pub active_changed: bool,
68}
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq)]
72pub enum DelayDoAction {
73 None,
75 ProcessAction,
77}
78
79pub struct DelayDoController {
81 pub state: DelayDoState,
82 pub delay_period: Duration,
84 resume_waiting: bool,
86 active_seen: bool,
88 wait_start: Option<Instant>,
90}
91
92impl Default for DelayDoController {
93 fn default() -> Self {
94 Self {
95 state: DelayDoState::Init,
96 delay_period: Duration::from_secs(0),
97 resume_waiting: false,
98 active_seen: false,
99 wait_start: None,
100 }
101 }
102}
103
104impl DelayDoController {
105 pub fn new(delay_secs: f64) -> Self {
106 Self {
107 delay_period: Duration::from_secs_f64(delay_secs),
108 ..Default::default()
109 }
110 }
111
112 pub fn step(&mut self, inputs: &DelayDoInputs) -> (DelayDoAction, DelayDoState) {
115 let action;
116
117 match self.state {
118 DelayDoState::Init => {
119 action = DelayDoAction::None;
120 self.resume_waiting = false;
121 self.state = DelayDoState::Idle;
122 }
123
124 DelayDoState::Disable => {
125 action = DelayDoAction::None;
126 if inputs.enable_changed && inputs.enable {
127 self.active_seen = false;
128 self.state = DelayDoState::MaybeStandby;
129 }
130 }
131
132 DelayDoState::MaybeStandby => {
133 action = DelayDoAction::None;
134 if inputs.standby {
135 self.state = DelayDoState::Standby;
136 } else if inputs.active {
137 self.state = DelayDoState::Active;
138 } else {
139 self.state = DelayDoState::Idle;
140 }
141 }
142
143 DelayDoState::Idle => {
144 action = DelayDoAction::None;
145 if inputs.enable_changed && !inputs.enable {
146 self.state = DelayDoState::Disable;
147 } else if inputs.standby_changed && inputs.standby {
148 self.state = DelayDoState::Standby;
149 } else if inputs.active_changed && inputs.active {
150 self.state = DelayDoState::Active;
151 }
152 }
153
154 DelayDoState::Standby => {
155 action = DelayDoAction::None;
156 if inputs.active_changed && inputs.active {
157 self.active_seen = true;
158 }
159 if inputs.enable_changed && !inputs.enable {
160 self.resume_waiting = false;
161 self.state = DelayDoState::Disable;
162 } else if inputs.standby_changed && !inputs.standby {
163 self.state = DelayDoState::MaybeWait;
164 }
165 }
166
167 DelayDoState::MaybeWait => {
168 action = DelayDoAction::None;
169 if inputs.active {
170 self.state = DelayDoState::Active;
171 } else if self.active_seen || self.resume_waiting {
172 self.active_seen = false;
173 self.wait_start = Some(Instant::now());
174 self.state = DelayDoState::Waiting;
175 } else {
176 self.state = DelayDoState::Idle;
177 }
178 }
179
180 DelayDoState::Active => {
181 action = DelayDoAction::None;
182 if inputs.enable_changed && !inputs.enable {
183 self.state = DelayDoState::Disable;
184 } else if inputs.standby_changed && inputs.standby {
185 self.state = DelayDoState::Standby;
186 } else if inputs.active_changed && !inputs.active {
187 self.wait_start = Some(Instant::now());
188 self.state = DelayDoState::Waiting;
189 }
190 }
191
192 DelayDoState::Waiting => {
193 if inputs.enable_changed && !inputs.enable {
194 action = DelayDoAction::None;
195 self.state = DelayDoState::Disable;
196 } else if inputs.standby_changed && inputs.standby {
197 action = DelayDoAction::None;
198 self.resume_waiting = true;
199 self.state = DelayDoState::Standby;
200 } else if inputs.active_changed && inputs.active {
201 action = DelayDoAction::None;
202 self.state = DelayDoState::Active;
203 } else if let Some(start) = self.wait_start {
204 if start.elapsed() >= self.delay_period {
205 self.resume_waiting = false;
206 self.wait_start = None;
207 self.state = DelayDoState::Action;
208 action = DelayDoAction::None;
209 } else {
210 action = DelayDoAction::None;
211 }
212 } else {
213 action = DelayDoAction::None;
214 }
215 }
216
217 DelayDoState::Action => {
218 action = DelayDoAction::ProcessAction;
219 self.state = DelayDoState::Idle;
220 }
221 }
222
223 (action, self.state)
224 }
225}