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);