1use core::borrow::BorrowMut;
2
3use alloc::boxed::Box;
4
5use config::{FatFsType, FormatConfiguration};
6
7use ::log::warn;
8
9use crate::hal::sd::SdCardDriver;
10use crate::sys::*;
11
12extern crate alloc;
13
14pub mod config {
15 #[derive(Copy, Clone, Eq, PartialEq)]
17 pub enum FatFsType {
18 Auto,
20 Fat,
22 Fat32,
24 ExFat,
26 }
27
28 pub struct FormatConfiguration {
30 pub fs_type: FatFsType,
32 #[cfg(not(esp_idf_version_major = "4"))]
34 pub fat_backup_copy: bool,
35 #[cfg(not(esp_idf_version_major = "4"))]
37 pub volume_data_alignment: core::num::NonZeroU16,
38 #[cfg(not(esp_idf_version_major = "4"))]
40 pub root_dir_entries: core::num::NonZeroU16,
41 pub cluster_size: u32,
43 }
44
45 impl FormatConfiguration {
46 pub const fn new() -> Self {
48 Self {
49 fs_type: FatFsType::Auto,
50 #[cfg(not(esp_idf_version_major = "4"))]
51 fat_backup_copy: false,
52 #[cfg(not(esp_idf_version_major = "4"))]
53 volume_data_alignment: unsafe { core::num::NonZeroU16::new_unchecked(1) },
54 #[cfg(not(esp_idf_version_major = "4"))]
55 root_dir_entries: unsafe { core::num::NonZeroU16::new_unchecked(512) },
56 cluster_size: 4096,
57 }
58 }
59 }
60
61 impl Default for FormatConfiguration {
62 fn default() -> Self {
63 Self::new()
64 }
65 }
66}
67
68enum Partition<T> {
69 SdCard(T),
70 RawPartition,
71}
72
73pub struct MountedFatfs<'a, T> {
79 fs: &'a mut Fatfs<T>,
80 fatfs: Box<FATFS>,
81}
82
83impl<T> MountedFatfs<'_, T> {
84 pub fn fatfs(&self) -> &FATFS {
86 &self.fatfs
87 }
88
89 }
91
92impl<T> Drop for MountedFatfs<'_, T> {
93 fn drop(&mut self) {
94 let drive_path = self.fs.drive_path();
95
96 let res = unsafe { f_mount(core::ptr::null_mut(), drive_path.as_ptr(), 0) };
97
98 if res != FRESULT_FR_OK {
99 panic!("Unmount failed: {res}");
100 }
101 }
102}
103
104pub struct Fatfs<T> {
106 drive: u8,
107 _partition: Partition<T>,
108}
109
110impl<T> Fatfs<T> {
111 pub fn new_sdcard<H>(drive: u8, mut sd_card_driver: T) -> Result<Self, EspError>
117 where
118 T: BorrowMut<SdCardDriver<H>>,
119 {
120 unsafe {
121 ff_diskio_register_sdmmc(
122 drive,
123 sd_card_driver.borrow_mut().card() as *const _ as *mut _,
124 );
125 }
126
127 Ok(Self {
128 drive,
129 _partition: Partition::SdCard(sd_card_driver),
130 })
131 }
132
133 pub fn drive(&self) -> u8 {
135 self.drive
136 }
137
138 pub fn format(
144 &mut self,
145 configuration: &FormatConfiguration,
146 buf: &mut [u8],
147 ) -> Result<(), EspError> {
148 let drive_path = self.drive_path();
149
150 #[cfg(not(esp_idf_version_major = "4"))]
151 {
152 let opt = MKFS_PARM {
153 fmt: match configuration.fs_type {
154 FatFsType::Auto => FM_ANY,
155 FatFsType::Fat => FM_FAT,
156 FatFsType::Fat32 => FM_FAT32,
157 FatFsType::ExFat => FM_EXFAT,
158 } as _,
159 au_size: configuration.cluster_size,
160 n_fat: if configuration.fat_backup_copy { 2 } else { 1 },
161 n_root: configuration.root_dir_entries.get() as _,
162 align: configuration.volume_data_alignment.get() as _,
163 };
164
165 unsafe {
166 f_mkfs(
167 drive_path.as_ptr(),
168 &opt,
169 buf.as_mut_ptr() as *mut _,
170 buf.len() as _,
171 );
172 }
173 }
174
175 #[cfg(esp_idf_version_major = "4")]
176 {
177 unsafe {
178 f_mkfs(
179 drive_path.as_ptr(),
180 match configuration.fs_type {
181 FatFsType::Auto => FM_ANY,
182 FatFsType::Fat => FM_FAT,
183 FatFsType::Fat32 => FM_FAT32,
184 FatFsType::ExFat => FM_EXFAT,
185 } as _,
186 configuration.cluster_size,
187 buf.as_mut_ptr() as *mut _,
188 buf.len() as _,
189 );
190 }
191 }
192
193 Ok(())
194 }
195
196 pub fn mount(&mut self) -> Result<MountedFatfs<'_, T>, EspError> {
198 let mut fatfs: Box<FATFS> = Box::default(); let drive_path = self.drive_path();
201
202 let res = unsafe { f_mount(&mut *fatfs, drive_path.as_ptr(), 0) };
203
204 if res != FRESULT_FR_OK {
205 warn!("Mount failed: {res}");
206 Err(EspError::from_infallible::<ESP_FAIL>())?
207 }
208
209 Ok(MountedFatfs { fs: self, fatfs })
210 }
211
212 pub(crate) fn drive_path_from(drive: u8) -> [core::ffi::c_char; 2] {
213 [drive as _, 0]
214 }
215
216 pub(crate) fn drive_path(&self) -> [core::ffi::c_char; 2] {
217 Self::drive_path_from(self.drive)
218 }
219}
220
221impl Fatfs<()> {
222 pub unsafe fn new_raw_part(
234 drive: u8,
235 partition: *const esp_partition_t,
236 ) -> Result<Self, EspError> {
237 unsafe {
238 ff_diskio_register_raw_partition(drive, partition);
239 }
240
241 Ok(Self {
242 drive,
243 _partition: Partition::RawPartition,
244 })
245 }
246
247 pub unsafe fn new_wl_part(drive: u8, partition: wl_handle_t) -> Result<Self, EspError> {
259 unsafe {
260 ff_diskio_register_wl_partition(drive, partition);
261 }
262
263 Ok(Self {
264 drive,
265 _partition: Partition::RawPartition,
266 })
267 }
268}
269
270impl<T> Drop for Fatfs<T> {
271 fn drop(&mut self) {
272 unsafe {
273 ff_diskio_register(self.drive, core::ptr::null_mut());
274 }
275 }
276}