peripheral_register/
lib.rs

1#![no_std]
2use core::convert::{From, Into};
3use core::marker::PhantomData;
4use core::slice::from_raw_parts_mut;
5
6pub struct RegisterValue(usize);
7
8impl From<u8> for RegisterValue {
9    fn from(value: u8) -> RegisterValue {
10        RegisterValue(value as usize)
11    }
12}
13
14impl From<u16> for RegisterValue {
15    fn from(value: u16) -> RegisterValue {
16        RegisterValue(value as usize)
17    }
18}
19
20impl From<u32> for RegisterValue {
21    fn from(value: u32) -> RegisterValue {
22        RegisterValue(value as usize)
23    }
24}
25
26impl From<RegisterValue> for u8 {
27    fn from(value: RegisterValue) -> u8 {
28        value.0 as u8
29    }
30}
31
32impl From<RegisterValue> for u16 {
33    fn from(value: RegisterValue) -> u16 {
34        value.0 as u16
35    }
36}
37
38impl From<RegisterValue> for u32 {
39    fn from(value: RegisterValue) -> u32 {
40        value.0 as u32
41    }
42}
43
44pub trait Field {
45    fn get_offset_length(&self) -> (usize, usize);
46
47    fn of(&self, value: usize) -> usize {
48        let (offset, length) = self.get_offset_length();
49        (value & ((1 << length) - 1)) << offset
50    }
51}
52
53pub enum NoField {}
54
55impl Field for NoField {
56    fn get_offset_length(&self) -> (usize, usize) {
57        return (0, 0);
58    }
59}
60
61pub enum Bits {
62    Of(usize, usize),
63}
64
65impl Field for Bits {
66    fn get_offset_length(&self) -> (usize, usize) {
67        match self {
68            Bits::Of(offset, length) => (*offset, *length),
69        }
70    }
71}
72
73#[derive(Copy, Clone, Debug)]
74pub struct Register<T, U: Field = NoField> {
75    pub value: T,
76    u: PhantomData<U>,
77}
78
79impl<T, U: Field> From<T> for Register<T, U> {
80    fn from(value: T) -> Register<T, U> {
81        Register {
82            value,
83            u: PhantomData,
84        }
85    }
86}
87
88impl<'a, T, U: Field> Into<&'a mut [T]> for Register<T, U> {
89    fn into(mut self) -> &'a mut [T] {
90        unsafe { from_raw_parts_mut(&mut self.value, 1) }
91    }
92}
93
94impl<T, U> Register<T, U>
95where
96    T: Into<RegisterValue> + From<RegisterValue> + Copy + Default,
97    U: Field,
98{
99    pub fn new(value: T) -> Self {
100        Self {
101            value: value,
102            u: PhantomData,
103        }
104    }
105
106    pub fn of(u: U, value: T) -> Self {
107        let mut v = Self {
108            value: Default::default(),
109            u: PhantomData,
110        };
111        v.set(u, value);
112        v
113    }
114
115    pub fn get(&self, u: U) -> T {
116        let (offset, length) = u.get_offset_length();
117        let mask = ((1 << length) - 1) << offset;
118        RegisterValue((self.value.into().0 >> offset) & mask).into()
119    }
120
121    pub fn is_set(&self, u: U) -> bool {
122        self.get(u).into().0 > 0
123    }
124
125    pub fn set(&mut self, u: U, value: T) {
126        let (offset, length) = u.get_offset_length();
127        let mask = ((1 << length) - 1) << offset;
128        let to_set = self.value.into().0 & !mask;
129        let usize_value = value.into().0;
130        self.value = RegisterValue(to_set | (usize_value << offset) & mask).into();
131    }
132
133    pub fn reset(&mut self, u: U) {
134        let (offset, length) = u.get_offset_length();
135        let mask = ((1 << length) - 1) << offset;
136        let to_set = self.value.into().0 & !mask;
137        self.value = RegisterValue(to_set).into();
138    }
139}
140
141#[macro_export]
142macro_rules! register_fields {
143    (
144        $(
145            $(#[$outer:meta])*
146            enum $name:ident {
147                $($field:ident = $offset:tt : $len:tt,)*
148            }
149        )*
150    ) => {
151        $(
152            $(#[$outer])*
153            #[repr(usize)]
154            #[derive(Copy, Clone)]
155            enum $name {
156                $($field = $offset << 8 | $len,)*
157            }
158
159            impl Field for $name {
160                fn get_offset_length(&self) -> (usize, usize) {
161                    (*self as usize >> 8, *self as usize & 0xFF)
162                }
163            }
164        )*
165    };
166    (
167        $(
168            $(#[$outer:meta])*
169            pub enum $name:ident {
170                $($field:ident = $offset:tt : $len:tt,)*
171            }
172        )*
173    ) => {
174        $(
175            $(#[$outer])*
176            #[repr(usize)]
177            #[derive(Copy, Clone)]
178            pub enum $name {
179                $($field = $offset << 8 | $len,)*
180            }
181
182            impl Field for $name {
183                fn get_offset_length(&self) -> (usize, usize) {
184                    (*self as usize >> 8, *self as usize & 0xFF)
185                }
186            }
187        )*
188    }
189}