Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

regs/macro.rs: add optional conversion from value into bit field enum member #1019

Merged
merged 8 commits into from Jun 26, 2018
Merged
23 changes: 23 additions & 0 deletions libraries/tock-register-interface/README.md
Expand Up @@ -110,6 +110,7 @@ There are three types provided by the register interface: `ReadOnly`,
ReadOnly<T: IntLike, R: RegisterLongName = ()>
.get() -> T // Get the raw register value
.read(field: Field<T, R>) -> T // Read the value of the given field
.read_as_enum<E>(field: Field<T, R>) -> Option<E> // Read value of the given field as a enum member
.is_set(field: Field<T, R>) -> bool // Check if one or more bits in a field are set
.matches_any(value: FieldValue<T, R>) -> bool // Check if any specified parts of a field match
.matches_all(value: FieldValue<T, R>) -> bool // Check if all specified parts of a field match
Expand All @@ -126,6 +127,7 @@ ReadWrite<T: IntLike, R: RegisterLongName = ()>
.get() -> T // Get the raw register value
.set(value: T) // Set the raw register value
.read(field: Field<T, R>) -> T // Read the value of the given field
.read_as_enum<E>(field: Field<T, R>) -> Option<E> // Read value of the given field as a enum member
.write(value: FieldValue<T, R>) // Write the value of one or more fields,
// overwriting other fields to zero
.modify(value: FieldValue<T, R>) // Write the value of one or more fields,
Expand Down Expand Up @@ -165,6 +167,17 @@ regs.cr.set(regs.cr.get() + 1);
// The type annotation is not necessary, but provided for clarity here.
let range: u8 = regs.cr.read(Control::RANGE);

// Or one can read `range` as a enum and `match` over it.
let range = regs.cr.read_as_enum(Control::RANGE);
match range {
Some(Control::RANGE::Value::Zero) => { /* ... */ }
Some(Control::RANGE::Value::One) => { /* ... */ }
Some(Control::RANGE::Value::Two) => { /* ... */ }
Some(Control::RANGE::Value::Three) => { /* ... */ }

None => unreachable!("invalid value")
}

// `en` will be 0 or 1
let en: u8 = regs.cr.read(Control::EN);

Expand Down Expand Up @@ -231,6 +244,16 @@ while !regs.s.matches_all(Status::TXCOMPLETE::SET +
// Or for checking whether any interrupts are enabled:
let any_ints = regs.s.matches_any(Status::TXINTERRUPT + Status::RXINTERRUPT);

// Also you can read a register with set of enumerated values as a enum and `match` over it:
let mode = regs.cr.read_as_enum(Status::MODE);

match mode {
Some(Status::MODE::FullDuplex) => { /* ... */ }
Some(Status::MODE::HalfDuplex) => { /* ... */ }

None => unreachable!("invalid value")
}

// -----------------------------------------------------------------------------
// LOCAL COPY
// -----------------------------------------------------------------------------
Expand Down
17 changes: 16 additions & 1 deletion libraries/tock-register-interface/src/macros.rs
Expand Up @@ -63,7 +63,7 @@ macro_rules! register_bitmasks {
$(#[$outer])*
pub mod $field {
#[allow(unused_imports)]
use $crate::regs::FieldValue;
use $crate::regs::{FieldValue, TryFromValue};
use super::$reg_desc;

$(
Expand Down Expand Up @@ -96,6 +96,21 @@ macro_rules! register_bitmasks {
$valname = $value,
)*
}

impl TryFromValue<$valtype> for Value {
type EnumType = Value;

fn try_from(v: $valtype) -> Option<Self::EnumType> {
match v {
$(
$(#[$inner])*
x if x == Value::$valname as $valtype => Some(Value::$valname),
)*

_ => Option::None
}
}
}
}
};
}
Expand Down
22 changes: 22 additions & 0 deletions libraries/tock-register-interface/src/regs.rs
Expand Up @@ -77,6 +77,14 @@ pub trait RegisterLongName {}

impl RegisterLongName for () {}

/// Conversion of raw register value into enumerated values member.
/// Implemented inside register_bitfields![] macro for each bit field.
pub trait TryFromValue<V> {
type EnumType;

fn try_from(v: V) -> Option<Self::EnumType>;
}

/// Read/Write registers.
pub struct ReadWrite<T: IntLike, R: RegisterLongName = ()> {
value: T,
Expand Down Expand Up @@ -118,6 +126,13 @@ impl<T: IntLike, R: RegisterLongName> ReadWrite<T, R> {
(self.get() & (field.mask << field.shift)) >> field.shift
}

#[inline]
pub fn read_as_enum<E: TryFromValue<T, EnumType = E>>(&self, field: Field<T, R>) -> Option<E> {
let val: T = self.read(field);

E::try_from(val)
}

#[inline]
pub fn extract(&self) -> LocalRegisterCopy<T, R> {
LocalRegisterCopy::new(self.get())
Expand Down Expand Up @@ -173,6 +188,13 @@ impl<T: IntLike, R: RegisterLongName> ReadOnly<T, R> {
(self.get() & (field.mask << field.shift)) >> field.shift
}

#[inline]
pub fn read_as_enum<E: TryFromValue<T, EnumType = E>>(&self, field: Field<T, R>) -> Option<E> {
let val: T = self.read(field);

E::try_from(val)
}

#[inline]
pub fn extract(&self) -> LocalRegisterCopy<T, R> {
LocalRegisterCopy::new(self.get())
Expand Down