Skip to content

Commit

Permalink
Merge pull request #874 from AdinAck/master
Browse files Browse the repository at this point in the history
Arbitrary Return Types for Register Modification Closures
  • Loading branch information
burrbull authored Oct 24, 2024
2 parents 4563540 + 69f2444 commit 89af369
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
- Skip generating `.add(0)` and `1 *` in accessors
- Bump MSRV of generated code to 1.76
- move `must_use` from methods to generic type
- Add `write_and`, `write_with_zero_and`, and `modify_and` register modifiers

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

Expand Down
127 changes: 126 additions & 1 deletion src/generate/generic_reg_vcell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,51 @@ impl<REG: Resettable + Writable> Reg<REG> {
.bits,
);
}

/// Writes bits to a `Writable` register and produce a value.
///
/// You can write raw bits into a register:
/// ```ignore
/// periph.reg.write_and(|w| unsafe { w.bits(rawbits); });
/// ```
/// or write only the fields you need:
/// ```ignore
/// periph.reg.write_and(|w| {
/// w.field1().bits(newfield1bits)
/// .field2().set_bit()
/// .field3().variant(VARIANT);
/// });
/// ```
/// or an alternative way of saying the same:
/// ```ignore
/// periph.reg.write_and(|w| {
/// w.field1().bits(newfield1bits);
/// w.field2().set_bit();
/// w.field3().variant(VARIANT);
/// });
/// ```
/// In the latter case, other fields will be set to their reset value.
///
/// Values can be returned from the closure:
/// ```ignore
/// let state = periph.reg.write_and(|w| State::set(w.field1()));
/// ```
#[inline(always)]
pub fn from_write<F, T>(&self, f: F) -> T
where
F: FnOnce(&mut W<REG>) -> T,
{
let mut writer = W {
bits: REG::RESET_VALUE & !REG::ONE_TO_MODIFY_FIELDS_BITMAP
| REG::ZERO_TO_MODIFY_FIELDS_BITMAP,
_reg: marker::PhantomData,
};
let result = f(&mut writer);

self.register.set(writer.bits);

result
}
}

impl<REG: Writable> Reg<REG> {
Expand All @@ -110,6 +155,30 @@ impl<REG: Writable> Reg<REG> {
.bits,
);
}

/// Writes 0 to a `Writable` register and produces a value.
///
/// Similar to `write`, but unused bits will contain 0.
///
/// # Safety
///
/// Unsafe to use with registers which don't allow to write 0.
#[inline(always)]
pub unsafe fn from_write_with_zero<F, T>(&self, f: F) -> T
where
F: FnOnce(&mut W<REG>) -> T,
{
let mut writer = W {
bits: REG::Ux::default(),
_reg: marker::PhantomData,
};

let result = f(&mut writer);

self.register.set(writer.bits);

result
}
}

impl<REG: Readable + Writable> Reg<REG> {
Expand Down Expand Up @@ -159,11 +228,67 @@ impl<REG: Readable + Writable> Reg<REG> {
.bits,
);
}

/// Modifies the contents of the register by reading and then writing it
/// and produces a value.
///
/// E.g. to do a read-modify-write sequence to change parts of a register:
/// ```ignore
/// let bits = periph.reg.modify(|r, w| {
/// let new_bits = r.bits() | 3;
/// unsafe {
/// w.bits(new_bits);
/// }
///
/// new_bits
/// });
/// ```
/// or
/// ```ignore
/// periph.reg.modify(|_, w| {
/// w.field1().bits(newfield1bits)
/// .field2().set_bit()
/// .field3().variant(VARIANT);
/// });
/// ```
/// or an alternative way of saying the same:
/// ```ignore
/// periph.reg.modify(|_, w| {
/// w.field1().bits(newfield1bits);
/// w.field2().set_bit();
/// w.field3().variant(VARIANT);
/// });
/// ```
/// Other fields will have the value they had before the call to `modify`.
#[inline(always)]
pub fn from_modify<F, T>(&self, f: F) -> T
where
for<'w> F: FnOnce(&R<REG>, &'w mut W<REG>) -> T,
{
let bits = self.register.get();

let mut writer = W {
bits: bits & !REG::ONE_TO_MODIFY_FIELDS_BITMAP | REG::ZERO_TO_MODIFY_FIELDS_BITMAP,
_reg: marker::PhantomData,
};

let result = f(
&R {
bits,
_reg: marker::PhantomData,
},
&mut writer,
);

self.register.set(writer.bits);

result
}
}

impl<REG: Readable> core::fmt::Debug for crate::generic::Reg<REG>
where
R<REG>: core::fmt::Debug
R<REG>: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Debug::fmt(&self.read(), f)
Expand Down

0 comments on commit 89af369

Please sign in to comment.