1#![no_std]
85
86pub mod fatfs {
87
88 pub mod diskio;
90 mod inc_bindings;
91
92 extern crate alloc;
93
94 use core::ptr;
95 use alloc::string::String;
96 use bitflags::bitflags;
97 use embassy_sync::{mutex::Mutex, blocking_mutex::raw::ThreadModeRawMutex};
98 use crate::fatfs::inc_bindings::*;
99
100 #[cfg(feature = "chrono")]
101 use chrono::{NaiveDateTime, Timelike, Datelike};
102
103 #[derive(Debug)]
104 #[derive(PartialEq)]
105 pub enum Error {
106 DiskError = FRESULT_FR_DISK_ERR as isize,
107 IntError = FRESULT_FR_INT_ERR as isize,
108 NotReady = FRESULT_FR_NOT_READY as isize,
109 NoFile = FRESULT_FR_NO_FILE as isize,
110 NoPath = FRESULT_FR_NO_PATH as isize,
111 InvalidName = FRESULT_FR_INVALID_NAME as isize,
112 Denied = FRESULT_FR_DENIED as isize,
113 Exists = FRESULT_FR_EXIST as isize,
114 InvalidObject = FRESULT_FR_INVALID_OBJECT as isize,
115 WriteProtected = FRESULT_FR_WRITE_PROTECTED as isize,
116 InvalidDrive = FRESULT_FR_INVALID_DRIVE as isize,
117 NotEnabled = FRESULT_FR_NOT_ENABLED as isize,
118 NoFileSystem = FRESULT_FR_NO_FILESYSTEM as isize,
119 MkfsAborted = FRESULT_FR_MKFS_ABORTED as isize,
120 Timeout = FRESULT_FR_TIMEOUT as isize,
121 Locked = FRESULT_FR_LOCKED as isize,
122 NotEnoughCore = FRESULT_FR_NOT_ENOUGH_CORE as isize,
123 TooManyOpenFiles = FRESULT_FR_TOO_MANY_OPEN_FILES as isize,
124 InvalidParameter = FRESULT_FR_INVALID_PARAMETER as isize
125 }
126
127 impl TryFrom<u32> for Error {
128 type Error = ();
129
130 fn try_from(v: u32) -> Result<Self, Self::Error> {
131 match v {
132 x if x == Error::DiskError as u32 => Ok(Error::DiskError),
133 x if x == Error::IntError as u32 => Ok(Error::IntError),
134 x if x == Error::NotReady as u32 => Ok(Error::NotReady),
135 x if x == Error::NoFile as u32 => Ok(Error::NoFile),
136 x if x == Error::NoPath as u32 => Ok(Error::NoPath),
137 x if x == Error::InvalidName as u32 => Ok(Error::InvalidName),
138 x if x == Error::Denied as u32 => Ok(Error::Denied),
139 x if x == Error::Exists as u32 => Ok(Error::Exists),
140 x if x == Error::InvalidObject as u32 => Ok(Error::InvalidObject),
141 x if x == Error::WriteProtected as u32 => Ok(Error::WriteProtected),
142 x if x == Error::InvalidDrive as u32 => Ok(Error::InvalidDrive),
143 x if x == Error::NotEnabled as u32 => Ok(Error::NotEnabled),
144 x if x == Error::NoFileSystem as u32 => Ok(Error::NoFileSystem),
145 x if x == Error::MkfsAborted as u32 => Ok(Error::MkfsAborted),
146 x if x == Error::Timeout as u32 => Ok(Error::Timeout),
147 x if x == Error::Locked as u32 => Ok(Error::Locked),
148 x if x == Error::NotEnoughCore as u32 => Ok(Error::NotEnoughCore),
149 x if x == Error::TooManyOpenFiles as u32 => Ok(Error::TooManyOpenFiles),
150 x if x == Error::InvalidParameter as u32 => Ok(Error::InvalidParameter),
151 _ => Err(()),
152 }
153 }
154 }
155
156 impl Default for FATFS {
157 fn default() -> FATFS {
158 FATFS {
159 fs_type: Default::default(),
160 pdrv: Default::default(),
161 ldrv: Default::default(),
162 n_fats: Default::default(),
163 wflag: Default::default(),
164 fsi_flag: Default::default(),
165 id: Default::default(),
166 n_rootdir: Default::default(),
167 csize: Default::default(),
168 last_clst: Default::default(),
169 free_clst: Default::default(),
170 n_fatent: Default::default(),
171 fsize: Default::default(),
172 volbase: Default::default(),
173 fatbase: Default::default(),
174 dirbase: Default::default(),
175 database: Default::default(),
176 winsect: Default::default(),
177 win: [0; 512],
178 lfnbuf: ptr::null_mut(),
179 cdir: Default::default(),
180 }
181 }
182 }
183
184 impl Default for FFOBJID {
185 fn default() -> Self {
186 Self {
187 fs: ptr::null_mut(),
188 id: Default::default(),
189 attr: Default::default(),
190 stat: Default::default(),
191 sclust: Default::default(),
192 objsize: Default::default(),
193 lockid: Default::default(),
194 }
195 }
196 }
197
198 impl Default for FIL {
199 fn default() -> Self {
200 Self {
201 obj: Default::default(),
202 flag: Default::default(),
203 err: Default::default(),
204 fptr: Default::default(),
205 clust: Default::default(),
206 sect: Default::default(),
207 dir_sect: Default::default(),
208 dir_ptr: ptr::null_mut(),
209 buf: [0; 512],
210 cltbl: ptr::null_mut()
211 }
212 }
213 }
214
215 impl Default for DIR {
216 fn default() -> Self {
217 Self {
218 obj: Default::default(),
219 dptr: Default::default(),
220 clust: Default::default(),
221 sect: Default::default(),
222 dir: ptr::null_mut(),
223 fn_: Default::default(),
224 blk_ofs: Default::default(),
225 pat: ptr::null_mut(),
226 }
227 }
228 }
229
230 impl Default for FILINFO {
231 fn default() -> Self {
232 Self {
233 fsize: Default::default(),
234 fdate: Default::default(),
235 ftime: Default::default(),
236 fattrib: Default::default(),
237 fname: [0; 256],
238 altname: Default::default(),
239 }
240 }
241 }
242
243 bitflags! {
244 pub struct FileOptions: u8 {
245 const Read = FA_READ as u8;
246 const Write = FA_WRITE as u8;
247 const OpenExisting = FA_OPEN_EXISTING as u8;
248 const CreateNew = FA_CREATE_NEW as u8;
249 const CreateAlways = FA_CREATE_ALWAYS as u8;
250 const OpenAlways = FA_OPEN_ALWAYS as u8;
251 const OpenAppend = FA_OPEN_APPEND as u8;
252 }
253 }
254
255 bitflags! {
256 pub struct FileAttributes: u8 {
257 const ReadOnly = AM_RDO as u8;
258 const Hidden = AM_HID as u8;
259 const System = AM_SYS as u8;
260 const Directory = AM_DIR as u8;
261 const Archive = AM_ARC as u8;
262 }
263 }
264
265 bitflags! {
266 pub struct FormatOptions: u8 {
267 const FAT = FM_FAT as u8;
268 const FAT32 = FM_FAT32 as u8;
269 const EXFAT = FM_EXFAT as u8;
270 const Any = FM_ANY as u8;
271 }
272 }
273
274 impl FileOptions {
275 pub fn as_u8(&self) -> u8 {
276 self.bits() as u8
277 }
278 }
279
280 impl FileAttributes {
281 pub fn as_u8(&self) -> u8 {
282 self.bits() as u8
283 }
284 }
285
286 impl FormatOptions {
287 pub fn as_u8(&self) -> u8 {
288 self.bits() as u8
289 }
290 }
291
292 pub type FileSystem = Mutex<ThreadModeRawMutex, RawFileSystem>;
293 pub type File = FIL;
294 pub type Directory = DIR;
295 pub type FileInfo = FILINFO;
296
297 pub static FS: FileSystem = Mutex::new(
300 RawFileSystem { fs:
301 FATFS {
302 fs_type: 0,
303 pdrv: 0,
304 ldrv: 0,
305 n_fats: 0,
306 wflag: 0,
307 fsi_flag: 0,
308 id: 0,
309 n_rootdir: 0,
310 csize: 0,
311 last_clst: 0,
312 free_clst: 0,
313 n_fatent: 0,
314 fsize: 0,
315 volbase: 0,
316 fatbase: 0,
317 dirbase: 0,
318 database: 0,
319 winsect: 0,
320 win: [0; 512],
321 lfnbuf: ptr::null_mut(),
322 cdir: 0,
323 }
324 });
325
326 pub struct RawFileSystem {
328 fs: FATFS
329 }
330
331 unsafe impl Send for RawFileSystem {}
332
333 impl RawFileSystem {
334 pub fn open(&self, path: &str, mode: FileOptions) -> Result<File, Error> {
336 let result;
337 let mut file = Default::default();
338 unsafe { result = f_open(ptr::addr_of_mut!(file), path.as_ptr().cast(), mode.as_u8());}
339 if result == FRESULT_FR_OK {
340 return Ok(file)
341 } else {
342 return Err(Error::try_from(result).unwrap())
343 }
344 }
345
346 pub fn close(&self, file: &mut File) -> Result<(), Error> {
348 let result;
349 unsafe { result = f_close(ptr::addr_of_mut!(*file)); }
350 if result == FRESULT_FR_OK {
351 return Ok(())
352 } else {
353 return Err(Error::try_from(result).unwrap())
354 }
355 }
356
357 pub fn read(&self, file: &mut File, buffer: &mut [u8]) -> Result<u32, Error> {
359 let result;
360 let mut bytes_read: UINT = 0;
361 unsafe { result = f_read(ptr::addr_of_mut!(*file), buffer.as_mut_ptr().cast(), buffer.len() as u32, ptr::addr_of_mut!(bytes_read)); }
362 if result == FRESULT_FR_OK {
363 return Ok(bytes_read)
364 } else {
365 return Err(Error::try_from(result).unwrap())
366 }
367 }
368
369 pub fn write(&self, file: &mut File, buffer: &[u8]) -> Result<u32, Error> {
371 let result;
372 let mut bytes_written: UINT = 0;
373 unsafe { result = f_write(ptr::addr_of_mut!(*file), buffer.as_ptr().cast(), buffer.len() as u32, ptr::addr_of_mut!(bytes_written)); }
374 if result == FRESULT_FR_OK {
375 return Ok(bytes_written)
376 } else {
377 return Err(Error::try_from(result).unwrap())
378 }
379 }
380
381 pub fn seek(&self, file: &mut File, offset: u32) -> Result<(), Error> {
383 let result;
384 unsafe { result = f_lseek(ptr::addr_of_mut!(*file), offset); }
385 if result == FRESULT_FR_OK {
386 return Ok(())
387 } else {
388 return Err(Error::try_from(result).unwrap())
389 }
390 }
391
392 pub fn truncate(&self, file: &mut File) -> Result<(), Error> {
394 let result;
395 unsafe { result = f_truncate(ptr::addr_of_mut!(*file)); }
396 if result == FRESULT_FR_OK {
397 return Ok(())
398 } else {
399 return Err(Error::try_from(result).unwrap())
400 }
401 }
402
403 pub fn sync(&self, file: &mut File) -> Result<(), Error> {
405 let result;
406 unsafe { result = f_sync(ptr::addr_of_mut!(*file)); }
407 if result == FRESULT_FR_OK {
408 return Ok(())
409 } else {
410 return Err(Error::try_from(result).unwrap())
411 }
412 }
413
414 pub fn opendir(&self, path: &str) -> Result<Directory, Error> {
416 let result;
417 let mut dir: Directory = Default::default();
418 unsafe { result = f_opendir(ptr::addr_of_mut!(dir), path.as_ptr().cast()); }
419 if result == FRESULT_FR_OK {
420 return Ok(dir)
421 } else {
422 return Err(Error::try_from(result).unwrap())
423 }
424 }
425
426 pub fn closedir(&self, dir: &mut Directory) -> Result<(), Error> {
428 let result;
429 unsafe { result = f_closedir(ptr::addr_of_mut!(*dir)); }
430 if result == FRESULT_FR_OK {
431 return Ok(())
432 } else {
433 return Err(Error::try_from(result).unwrap())
434 }
435 }
436
437 pub fn readdir(&self, dir: &mut Directory) -> Result<FileInfo, Error> {
440 let result;
441 let mut info: FileInfo = Default::default();
442 unsafe { result = f_readdir(ptr::addr_of_mut!(*dir), ptr::addr_of_mut!(info)); }
443 if result == FRESULT_FR_OK {
444 return Ok(info)
445 } else {
446 return Err(Error::try_from(result).unwrap())
447 }
448 }
449
450 pub fn findfirst(&self, path: &str, pattern: &str) -> Result<(Directory, FileInfo), Error> {
453 let result;
454 let mut info: FileInfo = Default::default();
455 let mut dir: Directory = Default::default();
456 unsafe { result = f_findfirst(ptr::addr_of_mut!(dir), ptr::addr_of_mut!(info), path.as_ptr().cast(), pattern.as_ptr().cast()); }
457 if result == FRESULT_FR_OK {
458 return Ok((dir, info))
459 } else {
460 return Err(Error::try_from(result).unwrap())
461 }
462 }
463
464 pub fn findnext(&self, dir: &mut Directory) -> Result<FileInfo, Error> {
466 let result;
467 let mut info: FileInfo = Default::default();
468 unsafe { result = f_findnext(ptr::addr_of_mut!(*dir), ptr::addr_of_mut!(info)); }
469 if result == FRESULT_FR_OK {
470 return Ok(info)
471 } else {
472 return Err(Error::try_from(result).unwrap())
473 }
474 }
475
476 pub fn mkdir(&self, path: &str) -> Result<(), Error> {
478 let result;
479 unsafe { result = f_mkdir(path.as_ptr().cast()); }
480 if result == FRESULT_FR_OK {
481 return Ok(())
482 } else {
483 return Err(Error::try_from(result).unwrap())
484 }
485 }
486
487 pub fn unlink(&self, path: &str) -> Result<(), Error> {
489 let result;
490 unsafe { result = f_unlink(path.as_ptr().cast()); }
491 if result == FRESULT_FR_OK {
492 return Ok(())
493 } else {
494 return Err(Error::try_from(result).unwrap())
495 }
496 }
497
498 pub fn rename(&self, old_path: &str, new_path: &str) -> Result<(), Error> {
500 let result;
501 unsafe { result = f_rename(old_path.as_ptr().cast(), new_path.as_ptr().cast()); }
502 if result == FRESULT_FR_OK {
503 return Ok(())
504 } else {
505 return Err(Error::try_from(result).unwrap())
506 }
507 }
508
509 pub fn stat(&self, path: &str) -> Result<FileInfo, Error> {
511 let result;
512 let mut info: FileInfo = Default::default();
513 unsafe { result = f_stat(path.as_ptr().cast(), ptr::addr_of_mut!(info)); }
514 if result == FRESULT_FR_OK {
515 return Ok(info)
516 } else {
517 return Err(Error::try_from(result).unwrap())
518 }
519 }
520
521 pub fn chmod(&self, path: &str, attr: FileAttributes, mask: FileAttributes) -> Result<(), Error> {
523 let result;
524 unsafe { result = f_chmod(path.as_ptr().cast(), attr.as_u8(), mask.as_u8()); }
525 if result == FRESULT_FR_OK {
526 return Ok(())
527 } else {
528 return Err(Error::try_from(result).unwrap())
529 }
530 }
531
532 #[cfg(feature = "chrono")]
534 pub fn utime(&self, path: &str, timestamp: NaiveDateTime) -> Result<(), Error> {
535 let result;
536 let year = timestamp.year() as u32;
537 let month = timestamp.month();
538 let day = timestamp.day();
539 let hour = timestamp.hour();
540 let minute = timestamp.minute();
541 let second = timestamp.second();
542 let mut info = FileInfo::default();
543 info.fdate = (((year - 1980) * 512) | month * 32 | day) as u16;
544 info.ftime = (hour * 2048 | minute * 32 | second / 2) as u16;
545 unsafe { result = f_utime(path.as_ptr().cast(), ptr::addr_of_mut!(info)); }
546 if result == FRESULT_FR_OK {
547 return Ok(())
548 } else {
549 return Err(Error::try_from(result).unwrap())
550 }
551 }
552
553 pub fn chdir(&self, path: &str) -> Result<(), Error> {
555 let result;
556 unsafe { result = f_chdir(path.as_ptr().cast()); }
557 if result == FRESULT_FR_OK {
558 return Ok(())
559 } else {
560 return Err(Error::try_from(result).unwrap())
561 }
562 }
563
564 pub fn chdrive(&self, path: &str) -> Result<(), Error> {
566 let result;
567 unsafe { result = f_chdrive(path.as_ptr().cast()); }
568 if result == FRESULT_FR_OK {
569 return Ok(())
570 } else {
571 return Err(Error::try_from(result).unwrap())
572 }
573 }
574
575 pub fn getcwd(&self, buffer: &mut String) -> Result<(), Error> {
578 let result;
579 unsafe { result = f_getcwd(buffer.as_mut_ptr().cast(), buffer.capacity() as u32); }
580 if result == FRESULT_FR_OK {
581 return Ok(())
582 } else {
583 return Err(Error::try_from(result).unwrap())
584 }
585 }
586
587 pub fn getfree(&self, path: &str) -> Result<u32, Error> {
589 let result;
590 let mut num_clusters = 0;
591 let mut fs_ptr: *mut FATFS = ptr::null_mut();
592 unsafe { result = f_getfree(path.as_ptr().cast(), ptr::addr_of_mut!(num_clusters), ptr::addr_of_mut!(fs_ptr)); }
593 if result == FRESULT_FR_OK {
594 return Ok(num_clusters)
595 } else {
596 return Err(Error::try_from(result).unwrap())
597 }
598 }
599
600 pub fn getlabel(&self, path: &str, label: &mut String) -> Result<u32, Error> {
603 let result;
604 let mut vsn = 0;
605 if label.capacity() < 34 { return Err(Error::InvalidParameter)
607 }
608 unsafe { result = f_getlabel(path.as_ptr().cast(), label.as_mut_ptr().cast(), ptr::addr_of_mut!(vsn)); }
609 if result == FRESULT_FR_OK {
610 return Ok(vsn)
611 } else {
612 return Err(Error::try_from(result).unwrap())
613 }
614 }
615
616 pub fn setlabel(&self, label: &str) -> Result<(), Error> {
618 let result;
619 unsafe { result = f_setlabel(label.as_ptr().cast()); }
620 if result == FRESULT_FR_OK {
621 return Ok(())
622 } else {
623 return Err(Error::try_from(result).unwrap())
624 }
625 }
626
627 pub fn expand(&self, file: &mut File, size: u32) ->Result<(), Error> {
629 let result;
630 unsafe { result = f_expand(ptr::addr_of_mut!(*file), size, 1); }
631 if result == FRESULT_FR_OK {
632 return Ok(())
633 } else {
634 return Err(Error::try_from(result).unwrap())
635 }
636 }
637
638 pub fn mount(&mut self) -> Result<(), Error> {
640 self.fs = FATFS::default();
641 let file_path = "";
642 let result;
643 unsafe { result = f_mount(ptr::addr_of_mut!(self.fs), file_path.as_ptr().cast(), 1); }
644 if result == FRESULT_FR_OK {
645 return Ok(())
646 } else {
647 return Err(Error::try_from(result).unwrap())
648 }
649 }
650
651 pub fn mkfs(&self, path: &str, format: FormatOptions, copies: u8, alignment: u32, au_size: u32, root_entries: u32) -> Result<(), Error> {
653 let result;
654 let mut work: [u8; FF_MAX_SS as usize] = [0; FF_MAX_SS as usize];
655 let parameters = MKFS_PARM {
656 fmt: format.as_u8(),
657 n_fat: copies,
658 align: alignment,
659 n_root: root_entries,
660 au_size: au_size,
661 };
662 unsafe { result = f_mkfs(path.as_ptr().cast(), ptr::addr_of!(parameters), work.as_mut_ptr().cast(), work.len() as u32); }
663 if result == FRESULT_FR_OK {
664 return Ok(())
665 } else {
666 return Err(Error::try_from(result).unwrap())
667 }
668 }
669
670 pub fn setcp(&self, code_page: u16) -> Result<(), Error> {
672 let result;
673 unsafe { result = f_setcp(code_page); }
674 if result == FRESULT_FR_OK {
675 return Ok(())
676 } else {
677 return Err(Error::try_from(result).unwrap())
678 }
679 }
680
681 pub fn putc(&self, file: &mut File, char: u8) -> Result<i32, Error> {
683 let result;
684 unsafe { result = f_putc(char as TCHAR, ptr::addr_of_mut!(*file)); }
685 if result >= 0 {
686 return Ok(result)
687 } else {
688 return Err(Error::Denied)
689 }
690 }
691
692 pub fn puts(&self, file: &mut File, string: &str) -> Result<i32, Error> {
694 let result;
695 unsafe { result = f_puts(string.as_ptr().cast(), ptr::addr_of_mut!(*file)); }
696 if result >= 0 {
697 return Ok(result)
698 } else {
699 return Err(Error::Denied)
700 }
701 }
702
703 pub fn gets(&self, file: &mut File, buffer: &mut String) -> Result<(), Error> {
706 let result;
707 unsafe { result = f_gets(buffer.as_mut_ptr().cast(), buffer.capacity() as i32, ptr::addr_of_mut!(*file)); }
708 if result != ptr::null_mut() {
709 return Ok(())
710 } else {
711 return Err(Error::Denied)
712 }
713 }
714
715 pub fn unmount(&self, path: &str) -> Result<(), Error> {
717 let result;
718 unsafe { result = f_mount(ptr::null_mut(), path.as_ptr().cast(), 0); }
719 if result == FRESULT_FR_OK {
720 return Ok(())
721 } else {
722 return Err(Error::try_from(result).unwrap())
723 }
724 }
725 }
726
727}
728