aquarium_control/utilities/
check_mutex_access_duration.rs1use crate::sensors::atlas_scientific::AtlasScientific;
10use crate::sensors::dht::Dht;
11use crate::sensors::ds18b20::Ds18b20;
12use crate::sensors::sensor_manager::SensorManager;
13use crate::sensors::tank_level_switch::TankLevelSwitch;
14use crate::thermal::heating::Heating;
15use crate::thermal::ventilation::Ventilation;
16use crate::utilities::channel_content::AquariumSignal;
17use crate::water::water_injection::WaterInjection;
18#[cfg(not(test))]
19use log::warn;
20use std::time::{Duration, Instant};
21
22pub trait CheckMutexAccessDurationTrait {
23 fn get_warn_lock(&self, key_opt: &Option<&AquariumSignal>) -> bool;
26
27 fn set_warn_lock(&mut self, key: &Option<&AquariumSignal>, value: bool);
30
31 #[cfg(test)]
33 fn record_access_duration_violation(&mut self, key_opt: &Option<&AquariumSignal>);
34
35 fn get_max_mutex_access_duration(&self) -> Duration;
37
38 #[cfg(not(test))]
40 fn get_location(&self) -> &str;
41
42 fn check_mutex_access_duration(
43 &mut self,
44 key_opt: Option<&AquariumSignal>,
45 instant_after_locking_mutex: Instant,
46 instant_before_locking_mutex: Instant,
47 ) {
48 let measured_mutex_access_duration =
50 instant_after_locking_mutex.duration_since(instant_before_locking_mutex);
51 let warn_lock = self.get_warn_lock(&key_opt);
52 if measured_mutex_access_duration > self.get_max_mutex_access_duration() {
53 if !warn_lock {
54 self.set_warn_lock(&key_opt, true);
55 #[cfg(not(test))]
56 warn!(target: self.get_location(),
57 "Access to mutex took too long. Allowed={}ms, Measured={}ms",
58 self.get_max_mutex_access_duration().as_millis(),
59 measured_mutex_access_duration.as_millis(),
60 );
61 cfg_if::cfg_if! {
63 if #[cfg(test)] {
64 self.record_access_duration_violation(&key_opt);
65 }
66 }
67 }
68 } else {
69 self.set_warn_lock(&key_opt, false);
70 }
71 }
72}
73
74impl CheckMutexAccessDurationTrait for TankLevelSwitch {
75 fn get_warn_lock(&self, _key_opt: &Option<&AquariumSignal>) -> bool {
78 self.lock_warn_max_mutex_access_duration
79 }
80
81 fn set_warn_lock(&mut self, _key_opt: &Option<&AquariumSignal>, value: bool) {
84 self.lock_warn_max_mutex_access_duration = value;
85 }
86
87 #[cfg(test)]
88 fn record_access_duration_violation(&mut self, _key_opt: &Option<&AquariumSignal>) {
91 self.mutex_access_duration_exceeded = true;
92 }
93
94 fn get_max_mutex_access_duration(&self) -> Duration {
97 self.max_mutex_access_duration
98 }
99
100 #[cfg(not(test))]
102 fn get_location(&self) -> &str {
103 "tank level switch"
104 }
105}
106
107impl CheckMutexAccessDurationTrait for Heating {
108 fn get_warn_lock(&self, _key_opt: &Option<&AquariumSignal>) -> bool {
111 self.lock_warn_max_mutex_access_duration
112 }
113
114 fn set_warn_lock(&mut self, _key_opt: &Option<&AquariumSignal>, value: bool) {
117 self.lock_warn_max_mutex_access_duration = value;
118 }
119
120 #[cfg(test)]
121 fn record_access_duration_violation(&mut self, _key_opt: &Option<&AquariumSignal>) {
124 self.mutex_access_duration_exceeded = true;
125 }
126
127 fn get_max_mutex_access_duration(&self) -> Duration {
130 self.max_mutex_access_duration
131 }
132
133 #[cfg(not(test))]
135 fn get_location(&self) -> &str {
136 "heating"
137 }
138}
139
140impl CheckMutexAccessDurationTrait for Ventilation {
141 fn get_warn_lock(&self, _key_opt: &Option<&AquariumSignal>) -> bool {
144 self.lock_warn_max_mutex_access_duration
145 }
146
147 fn set_warn_lock(&mut self, _key_opt: &Option<&AquariumSignal>, value: bool) {
150 self.lock_warn_max_mutex_access_duration = value;
151 }
152
153 #[cfg(test)]
154 fn record_access_duration_violation(&mut self, _key_opt: &Option<&AquariumSignal>) {
157 self.mutex_access_duration_exceeded = true;
158 }
159
160 fn get_max_mutex_access_duration(&self) -> Duration {
163 self.max_mutex_access_duration
164 }
165
166 #[cfg(not(test))]
168 fn get_location(&self) -> &str {
169 "ventilation"
170 }
171}
172
173impl CheckMutexAccessDurationTrait for Dht {
174 fn get_warn_lock(&self, _key_opt: &Option<&AquariumSignal>) -> bool {
177 self.lock_warn_max_mutex_access_duration
178 }
179
180 fn set_warn_lock(&mut self, _key_opt: &Option<&AquariumSignal>, value: bool) {
183 self.lock_warn_max_mutex_access_duration = value;
184 }
185
186 #[cfg(test)]
187 fn record_access_duration_violation(&mut self, _key_opt: &Option<&AquariumSignal>) {
190 self.mutex_access_duration_exceeded = true;
191 }
192
193 fn get_max_mutex_access_duration(&self) -> Duration {
196 self.max_mutex_access_duration
197 }
198
199 #[cfg(not(test))]
201 fn get_location(&self) -> &str {
202 "dht"
203 }
204}
205
206impl CheckMutexAccessDurationTrait for SensorManager {
207 fn get_warn_lock(&self, _key_opt: &Option<&AquariumSignal>) -> bool {
210 self.lock_warn_max_mutex_access_duration
211 }
212
213 fn set_warn_lock(&mut self, _key_opt: &Option<&AquariumSignal>, value: bool) {
216 self.lock_warn_max_mutex_access_duration = value;
217 }
218
219 #[cfg(test)]
220 fn record_access_duration_violation(&mut self, _key_opt: &Option<&AquariumSignal>) {
223 self.mutex_access_duration_exceeded = true;
224 }
225
226 fn get_max_mutex_access_duration(&self) -> Duration {
229 self.max_mutex_access_duration
230 }
231
232 #[cfg(not(test))]
234 fn get_location(&self) -> &str {
235 "dht"
236 }
237}
238
239impl CheckMutexAccessDurationTrait for WaterInjection {
240 fn get_warn_lock(&self, _key_opt: &Option<&AquariumSignal>) -> bool {
243 self.lock_warn_max_mutex_access_duration
244 }
245
246 fn set_warn_lock(&mut self, _key_opt: &Option<&AquariumSignal>, value: bool) {
249 self.lock_warn_max_mutex_access_duration = value;
250 }
251
252 #[cfg(test)]
253 fn record_access_duration_violation(&mut self, _key_opt: &Option<&AquariumSignal>) {
256 self.mutex_access_duration_exceeded = true;
257 }
258
259 fn get_max_mutex_access_duration(&self) -> Duration {
262 self.max_mutex_access_duration
263 }
264
265 #[cfg(not(test))]
267 fn get_location(&self) -> &str {
268 "water_injection"
269 }
270}
271
272impl CheckMutexAccessDurationTrait for Ds18b20 {
273 fn get_warn_lock(&self, _key_opt: &Option<&AquariumSignal>) -> bool {
276 self.lock_warn_max_mutex_access_duration
277 }
278
279 fn set_warn_lock(&mut self, _key: &Option<&AquariumSignal>, value: bool) {
282 self.lock_warn_max_mutex_access_duration = value;
283 }
284
285 #[cfg(test)]
286 fn record_access_duration_violation(&mut self, _key_opt: &Option<&AquariumSignal>) {
289 self.mutex_access_duration_exceeded = true;
290 }
291
292 fn get_max_mutex_access_duration(&self) -> Duration {
295 self.max_mutex_access_duration
296 }
297
298 #[cfg(not(test))]
300 fn get_location(&self) -> &str {
301 "ventilation"
302 }
303}
304impl CheckMutexAccessDurationTrait for AtlasScientific {
305 fn get_warn_lock(&self, key_opt: &Option<&AquariumSignal>) -> bool {
306 if key_opt.is_some() {
307 match key_opt.as_ref().unwrap() {
308 AquariumSignal::WaterTemperature => {
309 self.lock_warn_max_mutex_access_duration_temperature
310 }
311 AquariumSignal::pH => self.lock_warn_max_mutex_access_duration_ph,
312 AquariumSignal::Conductivity => {
313 self.lock_warn_max_mutex_access_duration_conductivity
314 }
315 _ => false, }
317 } else {
318 true
320 }
321 }
322
323 fn set_warn_lock(&mut self, key_opt: &Option<&AquariumSignal>, value: bool) {
324 if key_opt.is_some() {
325 match key_opt.as_ref().unwrap() {
326 AquariumSignal::WaterTemperature => {
327 self.lock_warn_max_mutex_access_duration_temperature = value
328 }
329 AquariumSignal::pH => self.lock_warn_max_mutex_access_duration_ph = value,
330 AquariumSignal::Conductivity => {
331 self.lock_warn_max_mutex_access_duration_conductivity = value
332 }
333 _ => {} }
335 }
336 }
337
338 #[cfg(test)]
339 #[cfg(test)]
342 fn record_access_duration_violation(&mut self, key_opt: &Option<&AquariumSignal>) {
343 if key_opt.is_some() {
344 match key_opt.as_ref().unwrap() {
345 AquariumSignal::WaterTemperature => {
346 self.mutex_temperature_access_duration_exceeded = true
347 }
348 AquariumSignal::pH => self.mutex_ph_access_duration_exceeded = true,
349 AquariumSignal::Conductivity => {
350 self.mutex_conductivity_access_duration_exceeded = true
351 }
352 _ => { }
353 }
354 }
355 }
356
357 fn get_max_mutex_access_duration(&self) -> Duration {
360 self.max_mutex_access_duration_millis
361 }
362
363 #[cfg(not(test))]
365 fn get_location(&self) -> &str {
366 "atlas_scientific"
367 }
368}