// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // FAT formmatted SD card access // ========== P A R T 2 ====================================== // This is the directory listing and handleing, uses the device // buffer to read and write the directory sections. The operations // performed in this section are for reading, directory writing // is in a later section. // NOTE This shares many words with fat-1-a and so the SID numbers // Must be the same. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // HISTORY: // Mar 2008 * Replaced [char] : with 58 emit because BVT gets confused // REQUIRES: // #URL-Inc "http://pin1.org/forthlib/flb/General/soft1.flb" sid=99 // #URL-lib "http://pin1.org/forthlib/flb/General/pinsel.flb" sid=100 // #URL-lib "http://pin1.org/forthlib/flb/General/SPI.flb" sid=101 // #URL-lib "http://pin1.org/forthlib/flb/SD-Card/MMC.flb" sid=102 // #URL-lib "http://pin1.org/forthlib/flb/SD-Card/fat-1.flb" // // CONSTANTS: // convenient to hold current file name here i think 12 vspace$ dir$ // // constants used as an offset into the directory for either creation // or modification times. 14 constant created // offset for creation and modifed dates 22 constant modified // // Converts an entry number to a Dbuff address, en# is the // entry number 0 being the first 1 the second etc. Returns the address // into the buffer // ***** Note this will also make sure that the correct // sector is loaded for writing : dir-entry ( en# -- address ) 32 * // address of current entry BytesSec d @ u/mod // split to entry+sector Dir d @ + // add director offset dup d-sec <> // need to get another sector? if dsec@ // get next sector else drop // current sector then dbuff + ; // useful for obtaining the directory entry address for the current // file handle : dirAdd ( [handle] -- add ) direntry f ; // get the address // ========= directory operations ============== // does not do subdirectories or long file names // // routines for extracting a directory entry information, all the words // expect to be given the starting adedress of the entry : filename@ ( add - string ) dir$ 11 move 0 dir$ 12 + c! dir$ ; : attrib@ ( add -- ) 11 + c@ ; : start-clust@ ( add --clust ) dup 20 + word16 16 lshift swap 26 + word16 + ; // returns a time word, set type to the constant for either created or // modified to obtain the desired result : c-dir-time ( add -- tword ) created + word16 ; // this the modified time : m-dir-time ( add -- tword ) modified + word16 ; // this the modified time : c-hours@ ( add -- hours ) c-dir-time 11 rshift ; : m-hours@ ( add -- hours ) m-dir-time 11 rshift ; : c-minutes@ ( add -- mins ) c-dir-time 5 rshift &3f and ; : m-minutes@ ( add -- mins ) m-dir-time 5 rshift &3f and ; : c-seconds@ ( add -- sec ) c-dir-time &1f and ; : m-seconds@ ( add -- sec ) m-dir-time &1f and ; : c-dir-date ( add -- tword ) created + 2 + word16 ; // the modified time : m-dir-date ( add -- tword ) modified + 2 + word16 ; // he modified time : c-year@ ( add -- year ) c-dir-date 9 rshift 1980 + ; : m-year@ ( add -- year ) m-dir-date 9 rshift 1980 + ; : c-month@ ( add -- month ) c-dir-date 5 rshift &f and ; : m-month@ ( add -- month ) m-dir-date 5 rshift &f and ; : c-day@ ( add -- sec ) c-dir-date &1f and ; : m-day@ ( add -- sec ) m-dir-date &1f and ; : filesize@ ( add -- size ) dup 28 + word16 swap 30 + word16 16 lshift + ; // // creates a packed time and date word, opposite to above // date and time for new directry entries : packtime { h m s -- ptime } h 11 lshift m 5 lshift + s + ; : packdate { y m d -- pdate } y 1980 - 9 lshift m 5 lshift + d + ; // --- storing into entry : filename! ( string add -- ) 11 move ; : attrib! ( val add -- ) 11 + c! ; : start-clust! ( val add -- ) >r dup 16 rshift r@ 20 + word16! // high &ffff and r> 26 + word16! ; // low : c-time! ( addr h m s -- [packtime] ) packtime swap 14 + word16! ; : c-date! ( addr y m d -- [packtime] ) packdate swap 16 + word16! ; : m-time! ( addr h m s -- [packtime] ) packtime swap 22 + word16! ; : m-date! ( addr y m d -- [packtime] ) packdate swap 24 + word16! ; : filesize! ( size add -- ) >r dup 16 rshift r@ 20 + word16! // high &0000ffff and r> 28 + word16! ; // low // =========== Directory printing ========================= // prints out date entry : dir-date. ( add -- ) dup m-day@ <# # # #> stype [char] / emit dup m-month@ <# # # #> stype [char] / emit m-year@ <# # # # # #> stype ; // prints out time entry : dir-time. ( add -- ) dup m-hours@ <# # # #> stype 58 emit dup m-minutes@ <# # # #> stype 58 emit m-seconds@ <# # # #> stype ; // dir entry will print out modified time and date with an offset of 6 // This prints whatever is in the array : dir. ( add -- ) dup cr filename@ stype tab // name dup dir-date. space dup dir-time. tab dup start-clust@ . tab filesize@ . ; // list the root directory of a card. The device buffer is used for this // it has been set to here - see fat-1-a. Device is the device attached // and is a number that begins with 0 // ( device ---) : ls ( -- ) -1 => d-sec // force new read RootEntries d @ // number of directory entries for i dir-entry // need address to check for first byte dup c@ 0= if drop unloop escape then c@ &e5 <> if i dir-entry dir. then next ; // =============== searching and finding ================= // This word takes a doted input and produces an output // suitable for using as a serch string within a directory // buffer // input is s-add and output is also s-add, takes a standard // 8+3 dotted format and converts it to 2 words with // psaces, s-add1 sould be able to take 11 charaters + // the 0 terminator // S-ADD MUST BE MIN 12 CHARATCERS : dot2pad { s-add --- s-add1 } int: len Ic Oc // lenght of string in count, out count v$: tmp 13 // string holder %@ tmp 11 bl fill // set tmp to all spaces s-add length => len begin s-add Ic + c@ // fetch character dup 46 = // check for . if 1 +> Ic // just inc input past . 8 => Oc // for ext drop else %@ tmp Oc + c! 1 +> Ic // increment counters 1 +> Oc then Ic len 1- > until 0 %@ tmp 11 + c! // terminator %@ tmp toupper // covert to upper case ; // given a dotted string e.g. fred.txt, this searches through // the directory and returns with -1 and ad pointing to the start // of the directory entry within the buffer, this also fills // dir# array and dir$ string, but returns the address as well // in case the directory needs to be updated : dir-search ( string --- en# -1 |0) int: str dot2pad => str // convert string to padded RootEntries d @ // search all for i dir-entry // get entry address to test for 1st char dup c@ 0= if drop 0 unloop escape then // get out end of search str swap s= // see if match - dont care about deleted entries if i -1 leave // leave address and -1 then next ; // ================ Public interface ========================== : <0>f.device ( device -- ) => d# ; // set device : <0>f.find ( name -- [array] ad -1|0 ) dir-search ; : <0>f.ls ( -- ) ls ; // dir of current device