lpc8xx_hal/usart/
flags.rs

1use super::instances::Instance;
2
3macro_rules! flags {
4    (
5        $(
6            $bit_pos:expr,
7            $access:ident,
8            $flag_or_interrupt:ident,
9            $name:ident,
10            $description:expr;
11        )*
12    ) => {
13        /// Used to query the state of USART flags
14        ///
15        /// See [`USART::is_flag_set`], [`usart::Tx::is_flag_set`], and
16        /// [`usart::Rx::is_flag_set`].
17        ///
18        /// [`USART::is_flag_set`]: struct.USART.html#method.is_flag_set
19        /// [`usart::Tx::is_flag_set`]: struct.Tx.html#method.is_flag_set
20        /// [`usart::Rx::is_flag_set`]: struct.Rx.html#method.is_flag_set
21        pub enum Flag {
22            $(
23                #[doc = $description]
24                $name,
25            )*
26        }
27
28        impl Flag {
29            pub(super) fn is_set<I: Instance>(&self) -> bool {
30                // Sound, as besides reading, we only write to a stateless
31                // register.
32                let usart = unsafe { &*I::REGISTERS };
33
34                match self {
35                    $(
36                        Self::$name => {
37                            let flag = usart.stat.read()
38                                .bits() & (0x1 << $bit_pos);
39                            flags!(@reset, $access, usart, $bit_pos);
40                            flag != 0
41                        }
42                    )*
43                }
44            }
45        }
46
47        flags!(@interrupts, () () $($flag_or_interrupt, $name, $description;)*);
48
49        impl Interrupts {
50            pub(super) fn enable<I: Instance>(&self) {
51                // Sound, as we only write to a stateless register.
52                let usart = unsafe { &*I::REGISTERS };
53
54                usart.intenset.write(|w| {
55                    let mut bits = 0;
56
57                    $(
58                        flags!(@set_bit,
59                            $flag_or_interrupt,
60                            self.$name, bits, $bit_pos
61                        );
62                    )*
63
64                    // Sound, as long as the flags specified in the macro match
65                    // the hardware.
66                    unsafe { w.bits(bits) }
67                })
68            }
69
70            pub(super) fn disable<I: Instance>(&self) {
71                // Sound, as we only write to a stateless register.
72                let usart = unsafe { &*I::REGISTERS };
73
74                usart.intenclr.write(|w| {
75                    let mut bits = 0;
76
77                    $(
78                        flags!(@set_bit,
79                            $flag_or_interrupt,
80                            self.$name, bits, $bit_pos
81                        );
82                    )*
83
84                    // Sound, as long as the flags specified in the macro match
85                    // the hardware.
86                    unsafe { w.bits(bits) }
87                })
88            }
89        }
90    };
91
92    (@reset, ro, $usart:expr, $bit_pos:expr) => {};
93    (@reset, w1, $usart:expr, $bit_pos:expr) => {
94        // Sound, as long as the flags specified in the macro match the
95        // hardware.
96        $usart.stat.write(|w| unsafe { w.bits(0x1 << $bit_pos) });
97    };
98
99    (@set_bit, flag, $flag:expr, $bits:expr, $bit_pos:expr) => {};
100    (@set_bit, both, $flag:expr, $bits:expr, $bit_pos:expr) => {
101        if $flag {
102            $bits |= 0x1 << $bit_pos;
103        }
104    };
105
106    // Here's a bit of a trick to work around the fact that macros must always
107    // evaluate to complete items, expressions, etc. A struct field is not a
108    // complete thing in that sense, so a macro can't generate one. It needs to
109    // generate the whole struct, which is what the following rules do.
110    //
111    // This variant gets called if the beginning of the input is only a flag. It
112    // Ignores the flag and passes the rest of the input on.
113    (@interrupts,
114        ($($output_ty:tt)*)
115        ($($output_init:tt)*)
116        flag, $name:ident, $description:expr;
117        $($input:tt)*
118    ) => {
119        flags!(@interrupts, ($($output_ty)*) ($($output_init)*) $($input)*);
120    };
121    // This variant gets called, if the beginning of the input if both flag and
122    // interrupt. It adds a field for the interrupt to the output and passes the
123    // rest of the input on.
124    (@interrupts,
125        ($($output_ty:tt)*)
126        ($($output_init:tt)*)
127        both, $name:ident, $description:expr;
128        $($input:tt)*
129    ) => {
130        flags!(@interrupts,
131            (
132                $($output_ty)*
133                #[doc = $description]
134                pub $name: bool,
135            )
136            (
137                $($output_init)*
138                $name: false,
139            )
140            $($input)*
141        );
142    };
143    // This variant gets called, if there is no more input to parse. If
144    // generates the final struct from the output that has built up so far.
145    (@interrupts,
146        ($($output_ty:tt)*)
147        ($($output_init:tt)*)
148    ) => {
149        /// Used to enable or disable USART interrupts
150        ///
151        /// See [`USART::enable_interrupts`], [`USART::disable_interrupts`],
152        /// [`usart::Tx::enable_interrupts`], [`usart::Tx::disable_interrupts`],
153        /// [`usart::Rx::enable_interrupts`], and
154        /// [`usart::Rx::disable_interrupts`].
155        ///
156        /// [`USART::enable_interrupts`]: struct.USART.html#method.enable_interrupts
157        /// [`USART::disable_interrupts`]: struct.USART.html#method.disable_interrupts
158        /// [`usart::Tx::enable_interrupts`]: struct.Tx.html#method.enable_interrupts
159        /// [`usart::Tx::disable_interrupts`]: struct.Tx.html#method.disable_interrupts
160        /// [`usart::Rx::enable_interrupts`]: struct.Rx.html#method.enable_interrupts
161        /// [`usart::Rx::disable_interrupts`]: struct.Rx.html#method.disable_interrupts
162        #[allow(non_snake_case)]
163        pub struct Interrupts {
164            $($output_ty)*
165        }
166
167        impl Default for Interrupts {
168            fn default() -> Self {
169                Self {
170                    $($output_init)*
171                }
172            }
173        }
174    };
175}
176
177flags!(
178     0, ro, both, RXRDY,      "Receiver ready";
179     1, ro, flag, RXIDLE,     "Receiver idle";
180     2, ro, both, TXRDY,      "Transmitter ready";
181     3, ro, both, TXIDLE,     "Transmitter idle";
182     4, ro, flag, CTS,        "CTS signal asserted";
183     5, w1, both, DELTACTS,   "Change of CTS signal detected";
184     6, ro, both, TXDIS,      "Transmitter disabled";
185     8, w1, both, OVERRUN,    "Overrun error";
186    10, ro, flag, RXBRK,      "Received break";
187    11, w1, both, DELTARXBRK, "RXBRK flag has changed state";
188    12, w1, both, START,      "Start detected";
189    13, w1, both, FRAMERR,    "Framing error";
190    14, w1, both, PARITYERR,  "Parity error";
191    15, w1, both, RXNOISE,    "Received noise";
192    16, w1, both, ABERR,      "Autobaud error";
193);