To use this file copy and paste this:    // #URL-lib "http://pin1.org/forthlib/flb/SD-Card/fat-4.flb"   into BV Terminal 3 or here to download.

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // ========== P A R T 4 ====================================== // This section is for write operations. It is much harder to write // to the card than to read from it as things such as creating // directory space, updating the fat, checking free space etc. need // to be considered // // RTC is needed for creating and modifying files, for devices without // an RTC then the words will need to be changed // This shares many words with fat-1-a, fat-2 and fat-3 so it should // have the same SID number // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

// 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/General/rtc.flb" sid=103 // #URL-lib "http://pin1.org/forthlib/flb/SD-Card/fat-1.flb" // #URL-lib "http://pin1.org/forthlib/flb/SD-Card/fat-2.flb" // #URL-lib "http://pin1.org/forthlib/flb/SD-Card/fat-3.flb"


Full Contents of File

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// ========== P A R T 4 ======================================
// This section is for write operations. It is much harder to write
// to the card than to read from it as things such as creating
// directory space, updating the fat, checking free space etc. need
// to be considered
//
// RTC is needed for creating and modifying files, for devices without
// an RTC then the words will need to be changed
// This shares many words with fat-1-a, fat-2 and fat-3 so it should
// have the same SID number
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

// 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/General/rtc.flb" sid=103
// #URL-lib "http://pin1.org/forthlib/flb/SD-Card/fat-1.flb"
// #URL-lib "http://pin1.org/forthlib/flb/SD-Card/fat-2.flb"
// #URL-lib "http://pin1.org/forthlib/flb/SD-Card/fat-3.flb"

// ========== FAT - Write ===========================
// write value to cluster, value is a 16 bit word that is
// written in intel format
: fatClust! ( val clust# -- -1|0)
    fatClust        // get address and sector of cluster within fat
    word16!          // write new value
    d-sec  Dsec!        // store back to card
;   
 
// gets next free cluster in fat, starting at start, use start=0
// to find the first free fat, then use this value to find the next
: fatNF ( start -- clust# [-1 is disk full] )
    1+
    TotalSec  d  @  SectClust  d  @  / // total number of clusters- index
    swap
    do
        i  fatClust@  0=
        if  i  leave  then
    loop
    dup  TotalSec  d  @  >  if  drop  -1  then        // disk full check
;         

// Serarch for first blank directory entry, directory space goes from
// DIR d @ to RootEntries d @, use e5 as blank or 00
// next free ditrectory entry, addr is within the current sector
// 0 indicates that the directoiry is full
// ** At this stage d# (device) should be set
// sector will be in d-sec
: nfde  ( -- en#, -1|0 )
        0          // leave marker
        RootEntries  d  @    // number of directory entries
        for
                i  dir-entry      // conver en# to address
                c@        // get firct char
                dup  &e5  =      // look for either e5 or 0
                swap  0=          // both inducate free
                or  if  drop  i  -1  leave  then
        next
;

// stores update date and time in the dir entry
// to the given entry address
: storeDT ( add -- )
    dup  rtc.time  m-time! 
    rtc.date  m-date!
;

// stores create date and time in the dir entry
// to the given entry address
: storeDTC ( add -- )
    dup  rtc.time  c-time! 
    rtc.date  c-date!
; 
 

// writes current directory entry to card, loads in correct sector
// first by using the curent file handle.
// This copies the directory entry in the fiile handle to the
// correct directory entry on the card
: dir!  ( -- )  
    dirAdd                                // source address
    en#  f  @                              // get entry number
    dir-entry                          // get destination address, also gets sector from card
    32  move                              // fron file handle to directory
    d-sec  Dsec!                      // store to card
;
   
// If a file is erased then all of the clusters except the current
// one needs to be set to 0 and the current cluster is set to &ffff
// If the file is removed form the system then all of the clusters
// including the current clutser need to be erased. This will erase
// ALL of the clusters including the current one
// NOTE THERE IS NO CHECK FOR GOING OVER END OF FAT
: erase-clusters  ( start-clust# -- [fat] )
        begin   
            dup      // save previous
            fatClust@    // get next
            swap  0  swap  fatClust!      // write 0 to previous, available
            dup  &fff8  >      // end marker
            over  0=  or    // error checking will end if 0 encountered as well
                if  0  swap  fatClust!  -1  else  0  then  // dont forget last one
        until
;

// when opening an existing file for writing or deleting a file
// the fat clusters need to be reset back to zero to free upthe
// filespace, clust is the starting cluster. All clusters in theFAT
// including this one will be set to 0
// NOTE This erases the contents but not the name of the file
// changes to the directory
: clearFile ( -- )
        IsOpen  f  @  -1  >  if  121  error  then      // abort if file not open
        dirAdd  start-clust@  dup  // get file starting cluster and make copy
// 12 dir# @ dup // get file starting cluster and make copy
        erase-clusters    // erase ALL clusters in file
        &ffff  swap  fatClust!    // first clust to &ffff
        // directory
        0  dirAdd  fileSize!  // set file size to 0
// 0 13 dir# ! // set file size to 0,
        dirAdd  storeDT              // update modified dates
        Dir!                    // update card with modified entry
;

// open existing file for wtiting, this will RESET the file
// in the sence that the contects will be erased
: w-reset ( string handle -- )  
    r-open    error#  0=
    if
        clearFile      // clear out clusters
    else
        ."  File  error  "  error#  .
    then
;

// deletes REMOVES directory entry, sets first byte to e5,
// frees up file space by setting all clusters to 0
// not this is a pure directory operation, the file is not opened so
// the file handle is not used
: deleteFile ( string -- )
    dir-search      // search in current device, fills array as wel
    if
        >r  r@  dir-entry                      // get address, save entry #
        start-clust@  dup        // cluster # start for this entry
        erase-clusters            // free up clusters in fat
        0  swap  fatClust!    // and set current cluster to 0
        &e5  r>  dir-entry  c!          // spoil name, dir-entry loads dbuff
        d-sec  Dsec!                      // store to card
        0  error
    else
        ."  file  not  found"  103  error
    then                           
;   

// gets the last cluster in a chain, given a starting cluster
// writing
: last-clust ( clust -- last )
    begin
          dup  fatClust@  dup  &fff7  >  if  drop  -1  else  swap  drop  0  then
    until
;                   

// creates directory entry where sting is in the form fred.txt
// a file does not exist at this present time so the file hanlde
// is not used
: createFile ( string -- )
    dup  dir-search  if  ."  File  exists  use  reset"  130  error  then
    dot2pad        // convert to padded string
    dir$  11  move    // save
    nfde                // gets next free dir entry
    if
        // update fat with ffff in next available cluster
        0  fatNF              // get next free fat cluster
        &ffff  over  fatClust!        // store to fat - start-clust on stack
        // directory operations, en# on stack from nfde
        swap  dir-entry    >r  // convert entry to an address, loads Dbuff
        r@  start-clust!        // store to start cluster
        dir$  r@  11  move  // name
        r@  storeDTC        // store DT create
        r@  storeDT        // store update dat and time
        0  r>  fileSize!  // set file size to 0
        d-sec  Dsec!                      // store to card
    else
        ."  card  full"
        131  error    // abort
    then
;

// given a logical sector it retruns a new file size based
// on the maximum of either the existing size or the new
// calculated size
: newFS ( sect -- new-filesize )
    1+        // not sure why I need an extra 1
    dirAdd  filesize@        // get existing file size
    swap  BytesSec  d  @    *
    max          // return largest
;         

// random write, file must be opened first
// writes contens of fatb to the given LOGICAL sector of that file
// Ls2Phys returns - 1 if the existing cluster is
// exceeded so this is used to create more space.
// This is more complex than it looks, the function is to get next free
// store to current and update current to what was the next free
// Directory size is updated but not stored, this is done in close
: w-random ( handle sect [fatb] -- )
    swap  =>  f#    // make sure correct dir is used
    IsOpen  f  @  -1  >  if  122  error  then      // abort if file not open
    dup  Ls2Phys          // see if within current range
    dup  0  <
    if
        // this is where new file space is created
        drop  // -1
        dup
        SectClust  d  @  / // get number of clusters, save size needed ltr
        dirAdd  start-clust@  last-clust  swap  // get last cluster in chain
        for
            dup  fatNF
            dup  rot  fatClust!      // keep updating empty clusters
        next
        &ffff  swap  fatClust!        // last one
        // re-calculate logical sector
        dup  newFS  dirAdd  filesize!  // new file size
        Ls2Phys
        sec!        // save
    else
        // can write this to existing file space
        sec!    // save it
        newFS  dirAdd  filesize!  // new file size using logical sector
    then
;

// closes an open file by writing current date and
// file size
: f-close ( file -- )            
    dup  0  devices  between
    if
        =>  f#                  // current file handle
        IsOpen  f  @  -1  >  if  122  error  then      // abort if file not open
        dirAdd  storeDT          // updata date and time
        dir!                        // put back to dir, wrandom updates file size
        0  isOpen  f  !            // closed
    else
        ."  handle  wrong  value"  145  error   
    then       
; 
     
// ================= Public interface =========================
: <0>f.create ( string handle -- -1|0 )     // creates and opens file
    over  createFile
    f.open 
;
: <0>f.reset ( string handle -- )   w-reset  ;  // open and new
: <0>f.del ( string -- )   deleteFile  ;  // deletes file
: <0>f.close ( handle -- )   f-close  ;  // closes, updates date + size
: <0>f.wrandom ( handle sector -- )   w-random  ;  // write random
// : <0>f.flush ( handle -- ) => f# f-sec sec! ; // flush any unwritten memory
// Use f.open for appending