Skip to content

Commit 89af369

Browse files
authored
Merge pull request #874 from AdinAck/master
Arbitrary Return Types for Register Modification Closures
2 parents 4563540 + 69f2444 commit 89af369

File tree

2 files changed

+127
-1
lines changed

2 files changed

+127
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
1616
- Skip generating `.add(0)` and `1 *` in accessors
1717
- Bump MSRV of generated code to 1.76
1818
- move `must_use` from methods to generic type
19+
- Add `write_and`, `write_with_zero_and`, and `modify_and` register modifiers
1920

2021
## [v0.33.5] - 2024-10-12
2122

src/generate/generic_reg_vcell.rs

Lines changed: 126 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,51 @@ impl<REG: Resettable + Writable> Reg<REG> {
8787
.bits,
8888
);
8989
}
90+
91+
/// Writes bits to a `Writable` register and produce a value.
92+
///
93+
/// You can write raw bits into a register:
94+
/// ```ignore
95+
/// periph.reg.write_and(|w| unsafe { w.bits(rawbits); });
96+
/// ```
97+
/// or write only the fields you need:
98+
/// ```ignore
99+
/// periph.reg.write_and(|w| {
100+
/// w.field1().bits(newfield1bits)
101+
/// .field2().set_bit()
102+
/// .field3().variant(VARIANT);
103+
/// });
104+
/// ```
105+
/// or an alternative way of saying the same:
106+
/// ```ignore
107+
/// periph.reg.write_and(|w| {
108+
/// w.field1().bits(newfield1bits);
109+
/// w.field2().set_bit();
110+
/// w.field3().variant(VARIANT);
111+
/// });
112+
/// ```
113+
/// In the latter case, other fields will be set to their reset value.
114+
///
115+
/// Values can be returned from the closure:
116+
/// ```ignore
117+
/// let state = periph.reg.write_and(|w| State::set(w.field1()));
118+
/// ```
119+
#[inline(always)]
120+
pub fn from_write<F, T>(&self, f: F) -> T
121+
where
122+
F: FnOnce(&mut W<REG>) -> T,
123+
{
124+
let mut writer = W {
125+
bits: REG::RESET_VALUE & !REG::ONE_TO_MODIFY_FIELDS_BITMAP
126+
| REG::ZERO_TO_MODIFY_FIELDS_BITMAP,
127+
_reg: marker::PhantomData,
128+
};
129+
let result = f(&mut writer);
130+
131+
self.register.set(writer.bits);
132+
133+
result
134+
}
90135
}
91136

92137
impl<REG: Writable> Reg<REG> {
@@ -110,6 +155,30 @@ impl<REG: Writable> Reg<REG> {
110155
.bits,
111156
);
112157
}
158+
159+
/// Writes 0 to a `Writable` register and produces a value.
160+
///
161+
/// Similar to `write`, but unused bits will contain 0.
162+
///
163+
/// # Safety
164+
///
165+
/// Unsafe to use with registers which don't allow to write 0.
166+
#[inline(always)]
167+
pub unsafe fn from_write_with_zero<F, T>(&self, f: F) -> T
168+
where
169+
F: FnOnce(&mut W<REG>) -> T,
170+
{
171+
let mut writer = W {
172+
bits: REG::Ux::default(),
173+
_reg: marker::PhantomData,
174+
};
175+
176+
let result = f(&mut writer);
177+
178+
self.register.set(writer.bits);
179+
180+
result
181+
}
113182
}
114183

115184
impl<REG: Readable + Writable> Reg<REG> {
@@ -159,11 +228,67 @@ impl<REG: Readable + Writable> Reg<REG> {
159228
.bits,
160229
);
161230
}
231+
232+
/// Modifies the contents of the register by reading and then writing it
233+
/// and produces a value.
234+
///
235+
/// E.g. to do a read-modify-write sequence to change parts of a register:
236+
/// ```ignore
237+
/// let bits = periph.reg.modify(|r, w| {
238+
/// let new_bits = r.bits() | 3;
239+
/// unsafe {
240+
/// w.bits(new_bits);
241+
/// }
242+
///
243+
/// new_bits
244+
/// });
245+
/// ```
246+
/// or
247+
/// ```ignore
248+
/// periph.reg.modify(|_, w| {
249+
/// w.field1().bits(newfield1bits)
250+
/// .field2().set_bit()
251+
/// .field3().variant(VARIANT);
252+
/// });
253+
/// ```
254+
/// or an alternative way of saying the same:
255+
/// ```ignore
256+
/// periph.reg.modify(|_, w| {
257+
/// w.field1().bits(newfield1bits);
258+
/// w.field2().set_bit();
259+
/// w.field3().variant(VARIANT);
260+
/// });
261+
/// ```
262+
/// Other fields will have the value they had before the call to `modify`.
263+
#[inline(always)]
264+
pub fn from_modify<F, T>(&self, f: F) -> T
265+
where
266+
for<'w> F: FnOnce(&R<REG>, &'w mut W<REG>) -> T,
267+
{
268+
let bits = self.register.get();
269+
270+
let mut writer = W {
271+
bits: bits & !REG::ONE_TO_MODIFY_FIELDS_BITMAP | REG::ZERO_TO_MODIFY_FIELDS_BITMAP,
272+
_reg: marker::PhantomData,
273+
};
274+
275+
let result = f(
276+
&R {
277+
bits,
278+
_reg: marker::PhantomData,
279+
},
280+
&mut writer,
281+
);
282+
283+
self.register.set(writer.bits);
284+
285+
result
286+
}
162287
}
163288

164289
impl<REG: Readable> core::fmt::Debug for crate::generic::Reg<REG>
165290
where
166-
R<REG>: core::fmt::Debug
291+
R<REG>: core::fmt::Debug,
167292
{
168293
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
169294
core::fmt::Debug::fmt(&self.read(), f)

0 commit comments

Comments
 (0)