Skip to content

Commit 0f3cb05

Browse files
committed
dedicated CID module
1 parent 4d842eb commit 0f3cb05

6 files changed

Lines changed: 2138 additions & 2015 deletions

File tree

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,10 @@ pub use crate::filesystem::{
111111
use filesystem::DirectoryInfo;
112112

113113
#[doc(inline)]
114-
pub use crate::sdcard::Error as SdCardError;
114+
pub use crate::sdcard::spi::Error as SdCardError;
115115

116116
#[doc(inline)]
117-
pub use crate::sdcard::SdCard;
117+
pub use crate::sdcard::spi::SdCard;
118118

119119
mod volume_mgr;
120120
#[doc(inline)]

src/sdcard/cid.rs

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
//! # CID support module
2+
3+
use arbitrary_int::{u7, u12, u40};
4+
5+
use crate::sdcard::crc7;
6+
7+
/// Checksum is invalid.
8+
#[derive(Debug, thiserror::Error)]
9+
#[error("checksum is invalid")]
10+
pub struct ChecksumInvalidError;
11+
12+
/// Card IDentification (CID) register structure.
13+
#[bitbybit::bitfield(u128, debug, defmt_fields(feature = "defmt-log"))]
14+
pub struct Cid {
15+
/// MID.
16+
#[bits(120..=127, rw)]
17+
manufacturer_id: u8,
18+
/// OID.
19+
#[bits(104..=119, rw)]
20+
oem_id: u16,
21+
/// PVM.
22+
#[bits(64..=103, rw)]
23+
product_name_raw: u40,
24+
/// PSN.
25+
#[bits(24..=55, rw)]
26+
product_serial_number: u32,
27+
/// MDT.
28+
#[bits(8..=19, rw)]
29+
manufacturing_date: u12,
30+
/// CRC.
31+
#[bits(1..=7, rw)]
32+
crc7: u7,
33+
}
34+
35+
impl Cid {
36+
/// Construct a [Cid] from a raw byte slice with 16 bytes.
37+
pub fn new(raw: &[u8; 16]) -> Result<Cid, ChecksumInvalidError> {
38+
let cid = Cid::new_with_raw_value(u128::from_be_bytes(*raw));
39+
if !cid.verify_crc7() {
40+
return Err(ChecksumInvalidError);
41+
}
42+
Ok(cid)
43+
}
44+
45+
/// Construct a [Cid] without verifying the checksum.
46+
pub fn new_unchecked(raw: &[u8; 16]) -> Cid {
47+
Cid::new_with_raw_value(u128::from_be_bytes(*raw))
48+
}
49+
50+
/// Verify CRC7 checksum.
51+
pub fn verify_crc7(&self) -> bool {
52+
let raw_bytes = self.raw_value().to_be_bytes();
53+
let calculated = crc7(&raw_bytes[0..15]);
54+
self.crc7().value() == calculated
55+
}
56+
57+
/// Product name as a byte array.
58+
#[inline]
59+
pub fn product_name_bytes(&self) -> [u8; 5] {
60+
self.product_name_raw().to_be_bytes()
61+
}
62+
}
63+
64+
#[cfg(test)]
65+
mod tests {
66+
use super::*;
67+
68+
#[test]
69+
fn basic_test() {
70+
// CID retrieved from a real SD card.
71+
let raw_cid = [
72+
0x12, 0x34, 0x56, 0x41, 0x53, 0x54, 0x43, 0x0, 0x20, 0x0, 0x0, 0xc, 0xef, 0x1, 0x65,
73+
0xef,
74+
];
75+
// This also verifies the checksum.
76+
let cid = Cid::new(&raw_cid);
77+
assert!(cid.is_ok());
78+
79+
let cid = cid.unwrap();
80+
// https://www.bahjeez.com/sd-card-manufacturer-ids/: Patriot.
81+
assert_eq!(cid.manufacturer_id(), 0x12);
82+
assert_eq!(cid.oem_id(), 0x3456);
83+
84+
let product_name_raw = cid.product_name_bytes();
85+
let product_name = core::str::from_utf8(&product_name_raw).unwrap();
86+
assert_eq!(product_name, "ASTC\0");
87+
}
88+
89+
#[test]
90+
fn basic_test_unchecked() {
91+
// CID retrieved from a real SD card.
92+
let raw_cid = [
93+
0x12, 0x34, 0x56, 0x41, 0x53, 0x54, 0x43, 0x0, 0x20, 0x0, 0x0, 0xc, 0xef, 0x1, 0x65,
94+
0x00,
95+
];
96+
// Invalid checksum ignored.
97+
let cid = Cid::new_unchecked(&raw_cid);
98+
assert!(!cid.verify_crc7());
99+
100+
// https://www.bahjeez.com/sd-card-manufacturer-ids/: Patriot.
101+
assert_eq!(cid.manufacturer_id(), 0x12);
102+
assert_eq!(cid.oem_id(), 0x3456);
103+
104+
let product_name_raw = cid.product_name_bytes();
105+
let product_name = core::str::from_utf8(&product_name_raw).unwrap();
106+
assert_eq!(product_name, "ASTC\0");
107+
}
108+
}

0 commit comments

Comments
 (0)