1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
use crate::lib_bitfield;
use crate::result::{Error, Result};
lib_bitfield! {
/// Represents the starting byte of card responses in SD mode.
pub Start(u8): u8 {
/// The MSB of the response, should always be `0`.
pub start_bit: 7;
/// The transmission bit, should always be `0`.
pub transmission_bit: 6;
/// Represents a 6-bit index ranging from `0-63`, indicating the `CMD` number for the response.
pub command_index: 5, 0;
}
}
impl Start {
/// Represents the byte length of the [Start].
pub const LEN: usize = 1;
/// Represents the default value of the [Start].
pub const DEFAULT: u8 = 0;
/// Represents the valid bitmask of the [Start].
pub const MASK: u8 = 0b0011_1111;
/// Creates a new [Start].
pub const fn new() -> Self {
Self(Self::DEFAULT)
}
/// Converts a [`u8`] into a [Start].
///
/// # Note
///
/// Masks the value to a valid [Start] value.
pub const fn from_bits(val: u8) -> Self {
Self(val & Self::MASK)
}
/// Attempts to convert a [`u8`] into a [Start].
pub const fn try_from_bits(val: u8) -> Result<Self> {
match val {
v if (v & !Self::MASK) != 0 => Err(Error::invalid_field_variant("start", v as usize)),
v => Ok(Self(v)),
}
}
}
impl Default for Start {
fn default() -> Self {
Self::new()
}
}
impl TryFrom<u8> for Start {
type Error = Error;
fn try_from(val: u8) -> Result<Self> {
Self::try_from_bits(val)
}
}
impl From<Start> for u8 {
fn from(val: Start) -> Self {
val.bits()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_fields() {
let mut s = Start::new();
assert_eq!(s.command_index(), 0);
assert!(!s.transmission_bit());
assert!(!s.start_bit());
(0..=0x3f).for_each(|cmd| {
s.set_command_index(cmd);
assert_eq!(s.command_index(), cmd);
// make sure we didn't corrupt other fields
assert!(!s.transmission_bit());
assert!(!s.start_bit());
});
// the interface will accept invalid command index, but masks the value.
(0x40..=u8::MAX).for_each(|invalid_cmd| {
s.set_command_index(invalid_cmd);
assert_eq!(s.command_index(), invalid_cmd & Start::MASK);
});
}
}