use core::fmt::{Debug, Formatter, UpperHex};
pub struct ConversionError<T: UpperHex + Debug> {
pub raw: T,
}
impl<T: UpperHex + Debug> Debug for ConversionError<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_struct("ConversionError")
.field("raw", &format_args!("0x{:X}", self.raw))
.finish()
}
}
pub trait RegisterInterface {
type Address;
type InterfaceError: Debug;
fn read_register(
&mut self,
address: Self::Address,
value: &mut [u8],
) -> Result<(), Self::InterfaceError>;
fn write_register(
&mut self,
address: Self::Address,
value: &[u8],
) -> Result<(), Self::InterfaceError>;
}
#[macro_export]
macro_rules! implement_registers {
(
$(#[$register_set_doc:meta])*
$device_name:ident.$register_set_name:ident<$register_address_type:ty> = {
$(
$(#[doc=$register_doc:literal])*
$(#[generate($($generate_list:tt)*)])?
$register_name:ident($register_access_specifier:tt, $register_address:tt, $register_size:expr) = $($register_bit_order:ident)? {
$(
$(#[$field_doc:meta])*
$field_name:ident: $field_type:ty $(:$field_bit_order:ident)? $(as $field_convert_type:ty)? = $field_access_specifier:tt $field_bit_range:expr
),* $(,)?
}
),* $(,)?
}
) => {
$(#[$register_set_doc])*
pub mod $register_set_name {
use super::*;
use device_driver::ll::register::{RegisterInterface, ConversionError};
use device_driver::ll::LowLevelDevice;
use device_driver::_implement_register;
use device_driver::_implement_register_field;
use device_driver::_get_bit_order;
use device_driver::_load_with_endianness;
use device_driver::_store_with_endianness;
use device_driver::generate_if_debug_keyword;
impl<'a, I: HardwareInterface> $device_name<I>
where
I: 'a + RegisterInterface<Address = $register_address_type>,
{
$(#[$register_set_doc])*
pub fn $register_set_name(&'a mut self) -> RegisterSet<'a, I> {
RegisterSet::new(&mut self.interface)
}
}
pub struct RegAccessor<'a, I, R, W>
where
I: 'a + RegisterInterface<Address = $register_address_type>,
{
interface: &'a mut I,
phantom: core::marker::PhantomData<(R, W)>,
}
impl<'a, I, R, W> RegAccessor<'a, I, R, W>
where
I: 'a + RegisterInterface<Address = $register_address_type>,
{
fn new(interface: &'a mut I) -> Self {
Self {
interface,
phantom: Default::default(),
}
}
}
pub struct RegisterSet<'a, I>
where
I: 'a + RegisterInterface<Address = $register_address_type>,
{
interface: &'a mut I,
}
impl<'a, I> RegisterSet<'a, I>
where
I: 'a + RegisterInterface<Address = $register_address_type>,
{
fn new(interface: &'a mut I) -> Self {
Self { interface }
}
$(
$(#[doc = $register_doc])*
pub fn $register_name(&'a mut self) -> RegAccessor<'a, I, $register_name::R, $register_name::W> {
RegAccessor::new(&mut self.interface)
}
)*
}
$(
$(#[doc = $register_doc])*
pub mod $register_name {
use super::*;
_implement_register!(
#[generate($($($generate_list)*)*)]
($register_name, $register_access_specifier, $register_address, $register_size, $register_address_type, _get_bit_order!($($register_bit_order)*)) {
$(
$(#[$field_doc])*
$field_name: $field_type $(:$field_bit_order)? $(as $field_convert_type)? = $field_access_specifier $field_bit_range
),*
}
);
}
)*
}
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! _implement_register {
(
#[generate($($generate_list:tt)*)]
($register_name:ident, @R, [$($register_address:expr),* $(,)?], $register_size:expr, $register_address_type:ty, $register_bit_order:ty) {
$(
$(#[$field_doc:meta])*
$field_name:ident: $field_type:ty $(:$field_bit_order:ident)? $(as $field_convert_type:ty)? = $field_access_specifier:tt $field_bit_range:expr
),*
}
) => {
#[derive(Copy, Clone)]
pub struct R([u8; $register_size]);
impl R {
pub const fn zero() -> Self {
Self([0; $register_size])
}
pub const fn from_raw(value: [u8; $register_size]) -> Self {
Self(value)
}
pub const fn get_raw(&self) -> [u8; $register_size] {
self.0
}
$(
_implement_register_field!(@R, $register_bit_order, $(#[$field_doc])* $field_name: $field_type $(:$field_bit_order)? $(as $field_convert_type)? = $field_access_specifier $field_bit_range);
)*
}
generate_if_debug_keyword!(
impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
f.debug_struct(concat!(stringify!($register_name), "::R"))
.field("raw", &device_driver::utils::SliceHexFormatter::new(&self.0))
$(
.field(stringify!($field_name), &self.$field_name())
)*
.finish()
}
},
impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
f.debug_struct(concat!(stringify!($register_name), "::R"))
.field("raw", &device_driver::utils::SliceHexFormatter::new(&self.0))
.finish()
}
},
$($generate_list)*
);
impl<'a, I> RegAccessor<'a, I, R, W>
where
I: RegisterInterface<Address = $register_address_type>,
{
pub fn read_index(&mut self, index: usize) -> Result<R, I::InterfaceError> {
let mut r = R::zero();
let addresses = [$($register_address,)*];
self.interface.read_register(addresses[index], &mut r.0)?;
Ok(r)
}
}
};
(
#[generate($($generate_list:tt)*)]
($register_name:ident, @R, $register_address:expr, $register_size:expr, $register_address_type:ty, $register_bit_order:ty) {
$(
$(#[$field_doc:meta])*
$field_name:ident: $field_type:ty $(:$field_bit_order:ident)? $(as $field_convert_type:ty)? = $field_access_specifier:tt $field_bit_range:expr
),*
}
) => {
#[derive(Copy, Clone)]
pub struct R(pub [u8; $register_size]);
impl R {
pub const fn zero() -> Self {
Self([0; $register_size])
}
pub const fn from_raw(value: [u8; $register_size]) -> Self {
Self(value)
}
pub const fn get_raw(&self) -> [u8; $register_size] {
self.0
}
$(
_implement_register_field!(@R, $register_bit_order, $(#[$field_doc])* $field_name: $field_type $(:$field_bit_order)? $(as $field_convert_type)? = $field_access_specifier $field_bit_range);
)*
}
generate_if_debug_keyword!(
impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
f.debug_struct(concat!(stringify!($register_name), "::R"))
.field("raw", &device_driver::utils::SliceHexFormatter::new(&self.0))
$(
.field(stringify!($field_name), &self.$field_name())
)*
.finish()
}
},
impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
f.debug_struct(concat!(stringify!($register_name), "::R"))
.field("raw", &device_driver::utils::SliceHexFormatter::new(&self.0))
.finish()
}
},
$($generate_list)*
);
impl<'a, I> RegAccessor<'a, I, R, W>
where
I: RegisterInterface<Address = $register_address_type>,
{
pub fn read(&mut self) -> Result<R, I::InterfaceError> {
let mut r = R::zero();
self.interface.read_register($register_address, &mut r.0)?;
Ok(r)
}
}
};
(
#[generate($($generate_list:tt)*)]
($register_name:ident, @W, [$($register_address:expr),* $(,)?], $register_size:expr, $register_address_type:ty, $register_bit_order:ty) {
$(
$(#[$field_doc:meta])*
$field_name:ident: $field_type:ty $(:$field_bit_order:ident)? $(as $field_convert_type:ty)? = $field_access_specifier:tt $field_bit_range:expr
),*
}
) => {
#[derive(Debug, Copy, Clone)]
pub struct W([u8; $register_size]);
impl W {
pub const fn zero() -> Self {
Self([0; $register_size])
}
pub const fn from_raw(value: [u8; $register_size]) -> Self {
Self(value)
}
pub const fn set_raw(self, value: [u8; $register_size]) -> Self {
Self(value)
}
$(
_implement_register_field!(@W, $register_bit_order, $(#[$field_doc])* $field_name: $field_type $(:$field_bit_order)? $(as $field_convert_type)? = $field_access_specifier $field_bit_range);
)*
}
impl<'a, I> RegAccessor<'a, I, R, W>
where
I: RegisterInterface<Address = $register_address_type>,
{
pub fn write_index<F>(&mut self, index: usize, f: F) -> Result<(), I::InterfaceError>
where
for<'w> F: FnOnce(&'w mut W) -> &'w mut W,
{
let mut w = W::zero();
let _ = f(&mut w);
self.write_index_direct(index, w)
}
fn write_index_direct(&mut self, index: usize, w: W) -> Result<(), I::InterfaceError> {
let addresses = [$($register_address,)*];
self.interface.write_register(addresses[index], &w.0)?;
Ok(())
}
}
};
(
#[generate($($generate_list:tt)*)]
($register_name:ident, @W, $register_address:expr, $register_size:expr, $register_address_type:ty, $register_bit_order:ty) {
$(
$(#[$field_doc:meta])*
$field_name:ident: $field_type:ty $(:$field_bit_order:ident)? $(as $field_convert_type:ty)? = $field_access_specifier:tt $field_bit_range:expr
),*
}
) => {
#[derive(Debug, Copy, Clone)]
pub struct W([u8; $register_size]);
impl W {
pub const fn zero() -> Self {
Self([0; $register_size])
}
pub const fn from_raw(value: [u8; $register_size]) -> Self {
Self(value)
}
pub const fn set_raw(self, value: [u8; $register_size]) -> Self {
Self(value)
}
$(
_implement_register_field!(@W, $register_bit_order, $(#[$field_doc])* $field_name: $field_type $(:$field_bit_order)? $(as $field_convert_type)? = $field_access_specifier $field_bit_range);
)*
}
impl<'a, I> RegAccessor<'a, I, R, W>
where
I: RegisterInterface<Address = $register_address_type>,
{
pub fn write<F>(&mut self, f: F) -> Result<(), I::InterfaceError>
where
for<'w> F: FnOnce(&'w mut W) -> &'w mut W,
{
let mut w = W::zero();
let _ = f(&mut w);
self.write_direct(w)
}
fn write_direct(&mut self, w: W) -> Result<(), I::InterfaceError> {
self.interface.write_register($register_address, &w.0)?;
Ok(())
}
}
};
(
#[generate($($generate_list:tt)*)]
($register_name:ident, RW, [$($register_address:expr),* $(,)?], $register_size:expr, $register_address_type:ty, $register_bit_order:ty) {
$(
$(#[$field_doc:meta])*
$field_name:ident: $field_type:ty $(:$field_bit_order:ident)? $(as $field_convert_type:ty)? = $field_access_specifier:tt $field_bit_range:expr
),*
}
) => {
_implement_register!(
#[generate($($generate_list)*)]
($register_name, @R, [$($register_address,)*], $register_size, $register_address_type, $register_bit_order) {
$(
$(#[$field_doc])*
$field_name: $field_type $(:$field_bit_order)? $(as $field_convert_type)? = $field_access_specifier $field_bit_range
),*
}
);
_implement_register!(
#[generate($($generate_list)*)]
($register_name, @W, [$($register_address,)*], $register_size, $register_address_type, $register_bit_order) {
$(
$(#[$field_doc])*
$field_name: $field_type $(:$field_bit_order)? $(as $field_convert_type)? = $field_access_specifier $field_bit_range
),*
}
);
impl<'a, I> RegAccessor<'a, I, R, W>
where
I: RegisterInterface<Address = $register_address_type>,
{
pub fn modify_index<F>(&mut self, index: usize, f: F) -> Result<(), I::InterfaceError>
where
for<'w> F: FnOnce(R, &'w mut W) -> &'w mut W,
{
let r = self.read_index(index)?;
let mut w = W(r.0.clone());
let _ = f(r, &mut w);
self.write_index_direct(index, w)?;
Ok(())
}
}
};
(
#[generate($($generate_list:tt)*)]
($register_name:ident, RW, $register_address:expr, $register_size:expr, $register_address_type:ty, $register_bit_order:ty) {
$(
$(#[$field_doc:meta])*
$field_name:ident: $field_type:ty $(:$field_bit_order:ident)? $(as $field_convert_type:ty)? = $field_access_specifier:tt $field_bit_range:expr
),*
}
) => {
_implement_register!(
#[generate($($generate_list)*)]
($register_name, @R, $register_address, $register_size, $register_address_type, $register_bit_order) {
$(
$(#[$field_doc])*
$field_name: $field_type $(:$field_bit_order)? $(as $field_convert_type)? = $field_access_specifier $field_bit_range
),*
}
);
_implement_register!(
#[generate($($generate_list)*)]
($register_name, @W, $register_address, $register_size, $register_address_type, $register_bit_order) {
$(
$(#[$field_doc])*
$field_name: $field_type $(:$field_bit_order)? $(as $field_convert_type)? = $field_access_specifier $field_bit_range
),*
}
);
impl<'a, I> RegAccessor<'a, I, R, W>
where
I: RegisterInterface<Address = $register_address_type>,
{
pub fn modify<F>(&mut self, f: F) -> Result<(), I::InterfaceError>
where
for<'w> F: FnOnce(R, &'w mut W) -> &'w mut W,
{
let r = self.read()?;
let mut w = W(r.0.clone());
let _ = f(r, &mut w);
self.write_direct(w)?;
Ok(())
}
}
};
(
#[generate($($generate_list:tt)*)]
($register_name:ident, RO, $register_address:tt, $register_size:expr, $register_address_type:ty, $register_bit_order:ty) {
$(
$(#[$field_doc:meta])*
$field_name:ident: $field_type:ty $(:$field_bit_order:ident)? $(as $field_convert_type:ty)? = $field_access_specifier:tt $field_bit_range:expr
),*
}
) => {
_implement_register!(
#[generate($($generate_list)*)]
($register_name, @R, $register_address, $register_size, $register_address_type, $register_bit_order) {
$(
$(#[$field_doc])*
$field_name: $field_type $(:$field_bit_order)? $(as $field_convert_type)? = $field_access_specifier $field_bit_range
),*
}
);
pub type W = ();
};
(
#[generate($($generate_list:tt)*)]
($register_name:ident, WO, $register_address:tt, $register_size:expr, $register_address_type:ty, $register_bit_order:ty) {
$(
$(#[$field_doc:meta])*
$field_name:ident: $field_type:ty $(:$field_bit_order:ident)? $(as $field_convert_type:ty)? = $field_access_specifier:tt $field_bit_range:expr
),*
}
) => {
_implement_register!(
#[generate($($generate_list)*)]
($register_name, @W, $register_address, $register_size, $register_address_type, $register_bit_order) {
$(
$(#[$field_doc])*
$field_name: $field_type $(:$field_bit_order)? $(as $field_convert_type)? = $field_access_specifier $field_bit_range
),*
}
);
pub type R = ();
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! _implement_register_field {
(@R, $register_bit_order:ty, $(#[$field_doc:meta])* $field_name:ident: $field_type:ty $(:$field_bit_order:ident)? = RO $field_bit_range:expr) => {
$(#[$field_doc])*
pub fn $field_name(&self) -> $field_type {
use device_driver::bitvec::prelude::*;
use device_driver::bitvec::view::AsBits;
_load_with_endianness!(self.0.as_bits::<$register_bit_order>()[$field_bit_range], $($field_bit_order)?)
}
};
(@R, $register_bit_order:ty, $(#[$field_doc:meta])* $field_name:ident: $field_type:ty $(:$field_bit_order:ident)? as $field_convert_type:ty = RO $field_bit_range:expr) => {
$(#[$field_doc])*
pub fn $field_name(&self) -> Result<$field_convert_type, ConversionError<$field_type>> {
use device_driver::bitvec::prelude::*;
use device_driver::bitvec::view::AsBits;
use core::convert::TryInto;
let raw: $field_type = _load_with_endianness!(self.0.as_bits::<$register_bit_order>()[$field_bit_range], $($field_bit_order)?);
raw.try_into().map_err(|_| ConversionError { raw })
}
};
(@R, $register_bit_order:ty, $(#[$field_doc:meta])* $field_name:ident: $field_type:ty $(:$field_bit_order:ident)? $(as $field_convert_type:ty)? = WO $field_bit_range:expr) => {
};
(@R, $register_bit_order:ty, $(#[$field_doc:meta])* $field_name:ident: $field_type:ty $(:$field_bit_order:ident)? $(as $field_convert_type:ty)? = RW $field_bit_range:expr) => {
_implement_register_field!(@R, $register_bit_order, $(#[$field_doc])* $field_name: $field_type $(:$field_bit_order)? $(as $field_convert_type)? = RO $field_bit_range);
_implement_register_field!(@R, $register_bit_order, $(#[$field_doc])* $field_name: $field_type $(:$field_bit_order)? $(as $field_convert_type)? = WO $field_bit_range);
};
(@W, $register_bit_order:ty, $(#[$field_doc:meta])* $field_name:ident: $field_type:ty $(:$field_bit_order:ident)? $(as $field_convert_type:ty)? = RO $field_bit_range:expr) => {
};
(@W, $register_bit_order:ty, $(#[$field_doc:meta])* $field_name:ident: $field_type:ty $(:$field_bit_order:ident)? = WO $field_bit_range:expr) => {
$(#[$field_doc])*
pub fn $field_name(&mut self, value: $field_type) -> &mut Self {
use device_driver::bitvec::prelude::*;
use device_driver::bitvec::view::AsBitsMut;
_store_with_endianness!(self.0.as_bits_mut::<$register_bit_order>()[$field_bit_range], value, $($field_bit_order)?);
self
}
};
(@W, $register_bit_order:ty, $(#[$field_doc:meta])* $field_name:ident: $field_type:ty $(:$field_bit_order:ident)? as $field_convert_type:ty = WO $field_bit_range:expr) => {
$(#[$field_doc])*
pub fn $field_name(&mut self, value: $field_convert_type) -> &mut Self {
use device_driver::bitvec::prelude::*;
use device_driver::bitvec::view::AsBitsMut;
let raw_value: $field_type = value.into();
_store_with_endianness!(self.0.as_bits_mut::<$register_bit_order>()[$field_bit_range], raw_value, $($field_bit_order)?);
self
}
};
(@W, $register_bit_order:ty, $(#[$field_doc:meta])* $field_name:ident: $field_type:ty $(:$field_bit_order:ident)? $(as $field_convert_type:ty)? = RW $field_bit_range:expr) => {
_implement_register_field!(@W, $register_bit_order, $(#[$field_doc])* $field_name: $field_type $(:$field_bit_order)? $(as $field_convert_type)? = RO $field_bit_range);
_implement_register_field!(@W, $register_bit_order, $(#[$field_doc])* $field_name: $field_type $(:$field_bit_order)? $(as $field_convert_type)? = WO $field_bit_range);
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! _get_bit_order {
() => {
Lsb0
};
(LSB) => {
Lsb0
};
(MSB) => {
Msb0
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! _load_with_endianness {
($field:expr, ) => {
_load_with_endianness!($field, BE)
};
($field:expr, BE) => {
$field.load_be()
};
($field:expr, LE) => {
$field.load_le()
};
($field:expr, NE) => {
$field.load()
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! _store_with_endianness {
($field:expr, $value:expr, ) => {
_store_with_endianness!($field, $value, BE)
};
($field:expr, $value:expr, BE) => {
$field.store_be($value)
};
($field:expr, $value:expr, LE) => {
$field.store_le($value)
};
($field:expr, $value:expr, NE) => {
$field.store($value)
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! generate_if_debug_keyword {
($true:item, $false:item, ) => {
$false
};
($true:item, $false:item, Debug) => {
$true
};
($true:item, $false:item, Debug, $($list:tt)*) => {
generate_if_debug_keyword!($true, $false, Debug);
};
($true:item, $false:item, $keyword:ident) => {
generate_if_debug_keyword!($true, $false, );
};
($true:item, $false:item, $keyword:ident, $($list:tt)*) => {
generate_if_debug_keyword!($true, $false, $($list)*);
};
}