trussed_core/
interrupt.rs

1use core::{
2    fmt::Debug,
3    sync::atomic::{AtomicU8, Ordering::Relaxed},
4};
5
6#[derive(Default, Debug, PartialEq, Eq)]
7pub enum InterruptState {
8    #[default]
9    Idle = 0,
10    Working = 1,
11    Interrupted = 2,
12}
13
14#[derive(Default, Debug, PartialEq, Eq, Clone)]
15pub struct FromU8Error;
16
17impl TryFrom<u8> for InterruptState {
18    type Error = FromU8Error;
19    fn try_from(value: u8) -> Result<Self, Self::Error> {
20        match value {
21            0 => Ok(Self::Idle),
22            1 => Ok(Self::Working),
23            2 => Ok(Self::Interrupted),
24            _ => Err(FromU8Error),
25        }
26    }
27}
28
29impl From<InterruptState> for u8 {
30    fn from(value: InterruptState) -> Self {
31        value as _
32    }
33}
34
35#[derive(Default)]
36pub struct InterruptFlag(AtomicU8);
37
38const CONV_ERROR: &str =
39    "Internal trussed error: InterruptState must always be set to an enum variant";
40
41impl InterruptFlag {
42    pub const fn new() -> Self {
43        Self(AtomicU8::new(0))
44    }
45    fn load(&self) -> InterruptState {
46        self.0.load(Relaxed).try_into().expect(CONV_ERROR)
47    }
48
49    pub fn set_idle(&self) {
50        self.0.store(InterruptState::Idle.into(), Relaxed)
51    }
52    pub fn set_working(&self) {
53        self.0.store(InterruptState::Working.into(), Relaxed)
54    }
55    pub fn interrupt(&self) -> bool {
56        self.0
57            .compare_exchange(
58                InterruptState::Working.into(),
59                InterruptState::Interrupted.into(),
60                Relaxed,
61                Relaxed,
62            )
63            .is_ok()
64    }
65
66    pub fn is_interrupted(&self) -> bool {
67        let res = self.load();
68        res == InterruptState::Interrupted
69    }
70}
71
72impl Debug for InterruptFlag {
73    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
74        self.load().fmt(f)
75    }
76}