mod bitfield;
mod command;
mod enums;
mod response;
#[macro_export]
macro_rules! bitflag_is_set {
($ty:ident) => {
impl $ty {
pub fn is_set(self, oth: Self) -> bool {
self & oth != Self::NONE
}
}
};
}
#[macro_export]
macro_rules! data_block {
(
$(#[$block_doc:meta])+
$block:ident: $block_len:expr,
$(#[$wide_block_doc:meta])+
$wide_block:ident: $wide_block_len:expr$(,)?
) => {
paste::paste! {
$(#[$block_doc])+
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct $block {
data: [u8; $block_len],
}
impl $block {
#[doc = "Creates a new [" $block "]."]
pub const fn new() -> Self {
Self {
data: [0u8; $block_len],
}
}
#[doc = "Creates a new [" $block "] from line data."]
pub const fn from_bytes(data: [u8; $block_len]) -> Self {
Self { data }
}
pub const fn data(&self) -> &[u8] {
&self.data
}
#[doc = "Converts the [" $block "] into a [" $wide_block "]."]
#[doc = ""]
#[doc = "This is for using all four `DAT` lines on a SD bus."]
pub const fn wide_data(&self) -> $wide_block {
use $crate::data::{wide_bus_encode, DataLine};
let mut wide = $wide_block::new();
let mut i = 0;
let len = self.data.len();
while i < len {
let b = self.data[i];
let dat_idx = i.saturating_div(WIDE_BUS_WIDTH);
wide.dat0[dat_idx] |= wide_bus_encode(b, i, DataLine::Dat0);
wide.dat1[dat_idx] |= wide_bus_encode(b, i, DataLine::Dat1);
wide.dat2[dat_idx] |= wide_bus_encode(b, i, DataLine::Dat2);
wide.dat3[dat_idx] |= wide_bus_encode(b, i, DataLine::Dat3);
i += 1;
}
wide
}
}
impl Default for $block {
fn default() -> Self {
Self::new()
}
}
$(#[$wide_block_doc])+
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct $wide_block {
dat0: [u8; $wide_block_len],
dat1: [u8; $wide_block_len],
dat2: [u8; $wide_block_len],
dat3: [u8; $wide_block_len],
}
impl $wide_block {
#[doc = "Creates a new [" $wide_block "]."]
pub const fn new() -> Self {
Self {
dat0: [0u8; $wide_block_len],
dat1: [0u8; $wide_block_len],
dat2: [0u8; $wide_block_len],
dat3: [0u8; $wide_block_len],
}
}
#[doc = "Creates a new [" $wide_block "] from `DAT` line data."]
pub const fn from_data_lines(
dat0: [u8; $wide_block_len],
dat1: [u8; $wide_block_len],
dat2: [u8; $wide_block_len],
dat3: [u8; $wide_block_len],
) -> Self {
Self {
dat0,
dat1,
dat2,
dat3,
}
}
#[doc = "Converts the [" $wide_block "] into a [" $block "]."]
#[doc = ""]
#[doc = "This is for using all four `DAT` lines on a SD bus."]
pub const fn decode(&self) -> $block {
use $crate::data::{wide_bus_decode, DataLine, WIDE_BUS_WIDTH};
let mut block = $block::new();
let mut i = 0;
let len = block.data.len();
while i < len {
let j = i.saturating_div(WIDE_BUS_WIDTH);
block.data[i] |= wide_bus_decode(self.dat0[j], i, DataLine::Dat0);
block.data[i] |= wide_bus_decode(self.dat1[j], i, DataLine::Dat1);
block.data[i] |= wide_bus_decode(self.dat2[j], i, DataLine::Dat2);
block.data[i] |= wide_bus_decode(self.dat3[j], i, DataLine::Dat3);
i += 1;
}
block
}
}
impl Default for $wide_block {
fn default() -> Self {
Self::new()
}
}
impl From<$block> for $wide_block {
fn from(val: $block) -> Self {
val.wide_data()
}
}
}
};
}
#[macro_export]
macro_rules! lib_struct {
(
$(#[$doc:meta])+
$ty:ident {
$($field:ident: $field_ty:ident$(,)?)+
}
) => {
paste::paste! {
$(#[$doc])+
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct $ty {
$($field: $field_ty,)+
}
impl $ty {
$(
#[doc = "Gets the [" $field_ty "] for the [" $ty "]."]
pub const fn $field(&self) -> $field_ty {
self.$field
}
#[doc = "Sets the [" $field_ty "] for the [" $ty "]."]
pub fn [<set_ $field>](&mut self, $field: $field_ty) {
self.$field = $field;
}
#[doc = "Builder function that sets the [" $field_ty "] for the [" $ty "]."]
pub const fn [<with_ $field>](self, $field: $field_ty) -> Self {
Self {
$field: $field,
..self
}
}
)+
}
}
}
}
#[macro_export]
macro_rules! test_field {
($t:ident, $field:ident) => {
paste::paste! {
$t.[<set_ $field>](true);
assert!($t.$field());
$t.[<set_ $field>](false);
assert!(!$t.$field());
}
};
($t:ident, $field:ident: $bit:expr) => {
paste::paste! {
$t.[<set_ $field>](true);
assert!($t.$field());
assert_eq!($t.bits() & (1 << $bit), 1 << $bit);
$t.[<set_ $field>](false);
assert!(!$t.$field());
assert_eq!($t.bits() & (1 << $bit), 0);
}
};
($t:ident, $field:ident { bit: $bit:expr, [$base:ty; $N:expr] }) => {
paste::paste! {
let idx = ($N - (($bit / $base::BITS) as usize) - 1);
let bit = $bit % $base::BITS;
$t.[<set_ $field>](true);
assert!($t.$field());
assert_eq!($t.bytes()[idx] & (1 << bit), 1 << bit);
$t.[<set_ $field>](false);
assert!(!$t.$field());
assert_eq!($t.bytes()[idx] & (1 << bit), 0);
}
};
}
#[macro_export]
macro_rules! const_try {
($e:expr) => {
match $e {
Ok(v) => v,
Err(err) => return Err(err),
}
};
}