11//! Filesystem related types
22
33use chrono:: { Datelike , Timelike } ;
4+ use embedded_sdmmc:: RawVolume ;
45
5- use crate :: { bios, API } ;
6+ use crate :: { bios, refcell :: CsRefCell , API , FILESYSTEM } ;
67
8+ /// Represents a block device that reads/writes disk blocks using the BIOS.
9+ ///
10+ /// Currently only block device 0 is supported.
711pub struct BiosBlock ( ) ;
812
913impl embedded_sdmmc:: BlockDevice for BiosBlock {
@@ -65,6 +69,7 @@ impl embedded_sdmmc::BlockDevice for BiosBlock {
6569 }
6670}
6771
72+ /// A type that lets you fetch the current time from the BIOS.
6873pub struct BiosTime ( ) ;
6974
7075impl embedded_sdmmc:: TimeSource for BiosTime {
@@ -81,4 +86,167 @@ impl embedded_sdmmc::TimeSource for BiosTime {
8186 }
8287}
8388
89+ /// The errors this module can produce
90+ #[ derive( Debug ) ]
91+ pub enum Error {
92+ /// Filesystem error
93+ Io ( embedded_sdmmc:: Error < bios:: Error > ) ,
94+ }
95+
96+ impl From < embedded_sdmmc:: Error < bios:: Error > > for Error {
97+ fn from ( value : embedded_sdmmc:: Error < bios:: Error > ) -> Self {
98+ Error :: Io ( value)
99+ }
100+ }
101+
102+ /// Represents an open file
103+ pub struct File {
104+ inner : embedded_sdmmc:: RawFile ,
105+ }
106+
107+ impl File {
108+ /// Read from a file
109+ pub fn read ( & self , buffer : & mut [ u8 ] ) -> Result < usize , Error > {
110+ FILESYSTEM . file_read ( self , buffer)
111+ }
112+
113+ /// Are we at the end of the file
114+ pub fn is_eof ( & self ) -> bool {
115+ FILESYSTEM
116+ . file_eof ( self )
117+ . expect ( "File handle should be valid" )
118+ }
119+
120+ /// Seek to a position relative to the start of the file
121+ pub fn seek_from_start ( & self , offset : u32 ) -> Result < ( ) , Error > {
122+ FILESYSTEM . file_seek_from_start ( self , offset)
123+ }
124+
125+ /// What is the length of this file?
126+ pub fn length ( & self ) -> u32 {
127+ FILESYSTEM
128+ . file_length ( self )
129+ . expect ( "File handle should be valid" )
130+ }
131+ }
132+
133+ impl Drop for File {
134+ fn drop ( & mut self ) {
135+ FILESYSTEM
136+ . close_raw_file ( self . inner )
137+ . expect ( "Should only be dropping valid files!" ) ;
138+ }
139+ }
140+
141+ /// Represent all open files and filesystems
142+ pub struct Filesystem {
143+ volume_manager : CsRefCell < Option < embedded_sdmmc:: VolumeManager < BiosBlock , BiosTime , 4 , 4 , 1 > > > ,
144+ first_volume : CsRefCell < Option < RawVolume > > ,
145+ }
146+
147+ impl Filesystem {
148+ /// Create a new filesystem
149+ pub const fn new ( ) -> Filesystem {
150+ Filesystem {
151+ volume_manager : CsRefCell :: new ( None ) ,
152+ first_volume : CsRefCell :: new ( None ) ,
153+ }
154+ }
155+
156+ /// Open a file on the filesystem
157+ pub fn open_file ( & self , name : & str , mode : embedded_sdmmc:: Mode ) -> Result < File , Error > {
158+ let mut fs = self . volume_manager . lock ( ) ;
159+ if fs. is_none ( ) {
160+ * fs = Some ( embedded_sdmmc:: VolumeManager :: new ( BiosBlock ( ) , BiosTime ( ) ) ) ;
161+ }
162+ let fs = fs. as_mut ( ) . unwrap ( ) ;
163+ let mut volume = self . first_volume . lock ( ) ;
164+ if volume. is_none ( ) {
165+ * volume = Some ( fs. open_raw_volume ( embedded_sdmmc:: VolumeIdx ( 0 ) ) ?) ;
166+ }
167+ let volume = volume. unwrap ( ) ;
168+ let mut root = fs. open_root_dir ( volume) ?. to_directory ( fs) ;
169+ let file = root. open_file_in_dir ( name, mode) ?;
170+ let raw_file = file. to_raw_file ( ) ;
171+ Ok ( File { inner : raw_file } )
172+ }
173+
174+ /// Walk through the root directory
175+ pub fn iterate_root_dir < F > ( & self , f : F ) -> Result < ( ) , Error >
176+ where
177+ F : FnMut ( & embedded_sdmmc:: DirEntry ) ,
178+ {
179+ let mut fs = self . volume_manager . lock ( ) ;
180+ if fs. is_none ( ) {
181+ * fs = Some ( embedded_sdmmc:: VolumeManager :: new ( BiosBlock ( ) , BiosTime ( ) ) ) ;
182+ }
183+ let fs = fs. as_mut ( ) . unwrap ( ) ;
184+ let mut volume = self . first_volume . lock ( ) ;
185+ if volume. is_none ( ) {
186+ * volume = Some ( fs. open_raw_volume ( embedded_sdmmc:: VolumeIdx ( 0 ) ) ?) ;
187+ }
188+ let volume = volume. unwrap ( ) ;
189+ let mut root = fs. open_root_dir ( volume) ?. to_directory ( fs) ;
190+ root. iterate_dir ( f) ?;
191+ Ok ( ( ) )
192+ }
193+
194+ /// Read from an open file
195+ pub fn file_read ( & self , file : & File , buffer : & mut [ u8 ] ) -> Result < usize , Error > {
196+ let mut fs = self . volume_manager . lock ( ) ;
197+ if fs. is_none ( ) {
198+ * fs = Some ( embedded_sdmmc:: VolumeManager :: new ( BiosBlock ( ) , BiosTime ( ) ) ) ;
199+ }
200+ let fs = fs. as_mut ( ) . unwrap ( ) ;
201+ let bytes_read = fs. read ( file. inner , buffer) ?;
202+ Ok ( bytes_read)
203+ }
204+
205+ /// How large is a file?
206+ pub fn file_length ( & self , file : & File ) -> Result < u32 , Error > {
207+ let mut fs = self . volume_manager . lock ( ) ;
208+ if fs. is_none ( ) {
209+ * fs = Some ( embedded_sdmmc:: VolumeManager :: new ( BiosBlock ( ) , BiosTime ( ) ) ) ;
210+ }
211+ let fs = fs. as_mut ( ) . unwrap ( ) ;
212+ let length = fs. file_length ( file. inner ) ?;
213+ Ok ( length)
214+ }
215+
216+ /// Seek a file with an offset from the start of the file.
217+ pub fn file_seek_from_start ( & self , file : & File , offset : u32 ) -> Result < ( ) , Error > {
218+ let mut fs = self . volume_manager . lock ( ) ;
219+ if fs. is_none ( ) {
220+ * fs = Some ( embedded_sdmmc:: VolumeManager :: new ( BiosBlock ( ) , BiosTime ( ) ) ) ;
221+ }
222+ let fs = fs. as_mut ( ) . unwrap ( ) ;
223+ fs. file_seek_from_start ( file. inner , offset) ?;
224+ Ok ( ( ) )
225+ }
226+
227+ /// Are we at the end of the file
228+ pub fn file_eof ( & self , file : & File ) -> Result < bool , Error > {
229+ let mut fs = self . volume_manager . lock ( ) ;
230+ if fs. is_none ( ) {
231+ * fs = Some ( embedded_sdmmc:: VolumeManager :: new ( BiosBlock ( ) , BiosTime ( ) ) ) ;
232+ }
233+ let fs = fs. as_mut ( ) . unwrap ( ) ;
234+ let is_eof = fs. file_eof ( file. inner ) ?;
235+ Ok ( is_eof)
236+ }
237+
238+ /// Close an open file
239+ ///
240+ /// Only used by File's drop impl.
241+ fn close_raw_file ( & self , file : embedded_sdmmc:: RawFile ) -> Result < ( ) , Error > {
242+ let mut fs = self . volume_manager . lock ( ) ;
243+ if fs. is_none ( ) {
244+ * fs = Some ( embedded_sdmmc:: VolumeManager :: new ( BiosBlock ( ) , BiosTime ( ) ) ) ;
245+ }
246+ let fs = fs. as_mut ( ) . unwrap ( ) ;
247+ fs. close_file ( file) ?;
248+ Ok ( ( ) )
249+ }
250+ }
251+
84252// End of file
0 commit comments