Shop OBEX P1 Docs P2 Docs Learn Events
FATEngine filename issue — Parallax Forums

FATEngine filename issue

TCP71TCP71 Posts: 38
edited 2011-06-16 09:09 in Propeller 1
I have a (probably simple) question. I'm using SD3.01_FATEngine and have mounted the disk and can manually write a file to it. I need to create/write to a file using a filename that I have stored in a variable string and changes every time I have new data to write. The filename is always 8.3 bytes and contains a ASCII characters. My code looks something like this:

VAR
Byte FileName[11] 'String of the latest filename
Byte CardData[400] 'Data to be written

Pub WriteFile | Counter, Char

Card.newFile(FileName[0..11])
Card.openFile(FileName[0..11)
Counter := 0
repeat
Counter++
Card.writeByte(CardData[Counter])
until (CardData[Counter] == $0A)
Card.closeFile

How do I format the "FileName[0..11]" part to take the 12 ASCII characters as the filename for newFile to use?
Any and all help, again, appreciated.

Comments

  • MacTuxLinMacTuxLin Posts: 821
    edited 2011-06-15 14:03
    Hmm, you should:
    VAR
       long fileName
    
    PUB Main
    
      fileName := String("thehello.txt")
    
      Card.newFile(fileName)
    
  • TCP71TCP71 Posts: 38
    edited 2011-06-15 14:36
    sorry, i don't see it. I don't have any problem creating the unique filename. I have a problem getting "Card.newFile(xxxxxxxx)" from accepting the 12 bytes of ASCII data that contain the unique file name. If it were a CON or "thehello.txt" it would be no problem, but Card.newFile doesn't like my 12 bytes of ASCII characters in any way that I can think of to provide them.
  • william chanwilliam chan Posts: 1,326
    edited 2011-06-15 14:47
    I am having the same problem with dynamic filenames.
    I am also having problems detecting whether a file exists or not.
  • SapiehaSapieha Posts: 2,964
    edited 2011-06-15 14:48
    Hi TCP71.

    If I know correctly --- You can only use 8+3 type filenames.

    12345678.123

    TCP71 wrote: »
    sorry, i don't see it. I don't have any problem creating the unique filename. I have a problem getting "Card.newFile(xxxxxxxx)" from accepting the 12 bytes of ASCII data that contain the unique file name. If it were a CON or "thehello.txt" it would be no problem, but Card.newFile doesn't like my 12 bytes of ASCII characters in any way that I can think of to provide them.
  • TCP71TCP71 Posts: 38
    edited 2011-06-15 15:00
    I have an 8.3 filename. They ASCII characters that make up that file name are stored in the variable.


    VAR
    Byte FileName[11] 'String of the latest filename

    The 11 bytes that make up the 8.3 filename are from 0 to 11(including the period). I need to get them from the FileName[11] into newFile(xxxxxxxx.xxx) position so newFile will use the name to create the file on the disk. For example, my variable FileName[11] contains the ascii characters "ITSATEST.TST" in order from 0 to 11. How do I get CARD.newFile(xxxxxxxx.xxx) to accept my FileName variable as an actual filename to use?
  • Dave HeinDave Hein Posts: 6,347
    edited 2011-06-15 15:15
    I've never used FATEngine, but I'm sure it is expecting a pointer to the filename. You should pass it as @FileName instead of FileName[0..11]. I don't think the compiler will even compile FileName[0..11]. Also, 8.3 filenames contain 12 characters plus a terminating null, so you should delay FileName to be at least 13 bytes in size. Open file also requires a mode parameter.
  • SapiehaSapieha Posts: 2,964
    edited 2011-06-15 15:17
    Hi TCP71.

    I don't looked on FATEngine - But normally in DOS You need omit period before You send that to write to Directory name
    12345678123

    TCP71 wrote: »
    I have an 8.3 filename. They ASCII characters that make up that file name are stored in the variable.


    VAR
    Byte FileName[11] 'String of the latest filename

    The 11 bytes that make up the 8.3 filename are from 0 to 11(including the period). I need to get them from the FileName[11] into newFile(xxxxxxxx.xxx) position so newFile will use the name to create the file on the disk. For example, my variable FileName[11] contains the ascii characters "ITSATEST.TST" in order from 0 to 11. How do I get CARD.newFile(xxxxxxxx.xxx) to accept my FileName variable as an actual filename to use?
  • Mike GreenMike Green Posts: 23,101
    edited 2011-06-15 15:29
    The FATEngine as well as FSRW expect to be passed the address of a zero-byte terminated string containing an 8.3 file name. This consists of 1 to 8 ASCII characters, followed by a decimal point, followed by 0 to 3 ASCII characters (followed by the zero byte). The ASCII characters have to be those allowed in a FAT file name.
  • william chanwilliam chan Posts: 1,326
    edited 2011-06-15 19:15
    Mike,

    What is the easiest way to create a dynamic filename string according to the date to pass to FATEngine?
    For example, If I want the file name to be

    ATDDMMYY.TXT

    where DD is the date, MM is the month and YY is the 2 digit year.
    SPIN does not have a sprintf command...
  • Mike GreenMike Green Posts: 23,101
    edited 2011-06-15 20:42
    var byte str [ 13 ]

    str[ 2 ] := (day / 10) + "0"
    str[ 3 ] := (day // 10) + "0"

    You do the same sort of thing for the month and year, use bytemove to copy in the "AT" and the ".TXT" with its zero byte terminator.
  • JLockeJLocke Posts: 354
    edited 2011-06-15 20:48
    Here's a logging function I use which automatically updates the filename to be the current date:
    PUB cog_logData | crntDay, minit
      ''* writes current data to SD on schedule (every 15 minutes)
      ''
      ' == cog initialization ==
      waitcnt((clkfreq * 2) + cnt)                        ' wait for date/time to be valid
      ByteFill(@fName, 0, FNAMESIZE)                      ' clear the filename buffer
      
      Str.Concatenate(@fName, SimplNum.decx(year, 2))     ' build the filename
      Str.Concatenate(@fName, string("-"))
      Str.Concatenate(@fName, SimplNum.decx(month, 2))
      Str.Concatenate(@fName, string("-"))
      Str.Concatenate(@fName, SimplNum.decx(day, 2))
      Str.Concatenate(@fName, string(".csv"))             ' save as '.csv' file
    
      Drv.mount(0)                                        ' mount the disk
      Drv.popen(@fName, "a")                              ' open the file
      Drv.sdstr(string("=== REBOOT ===", 13))             ' add indicator line
      Drv.sdstr(@FileHeader)                              ' add header line
      Drv.sdstr(string(" ", 13))                          ' blank line
      Drv.pclose                                          ' flush and close the file  
    
      crntDay := day                                      ' init the triggers
      minit   := minute
    
      ' == cog loop ==
      repeat                                              ' loop
        if crntDay <> day                                 ' &#9500;&#9472; day changed?
          crntDay := day                                  ' &#9474;  &#9500;&#9472; copy the new value
          ByteFill(@fName, 0, FNAMESIZE)                  ' &#9474;  &#9500;&#9472; clear the filename buffer
                                                          ' &#9474;  &#9474;   Build the filename
          Str.Concatenate(@fName, SimplNum.decx(year, 2)) ' &#9474;  &#9500;&#9472;   start with the year
          Str.Concatenate(@fName, string("-"))            ' &#9474;  &#9500;&#9472;   dash -
          Str.Concatenate(@fName, SimplNum.decx(month, 2))' &#9474;  &#9500;&#9472;   month
          Str.Concatenate(@fName, string("-"))            ' &#9474;  &#9500;&#9472;   dash -
          Str.Concatenate(@fName, SimplNum.decx(day, 2))  ' &#9474;  &#9500;&#9472;   day
          Str.Concatenate(@fName, string(".csv"))         ' &#9474;  &#9500;&#9472;   comma-separated values
                                                          ' &#9474;  &#9474;
          Drv.mount(0)                                    ' &#9474;  &#9500;&#9472; mount the disk
          Drv.popen(@fName, "a")                          ' &#9474;  &#9500;&#9472; open the file
          Drv.sdstr(string(" ", 13))                      ' &#9474;  &#9500;&#9472; blank line
          Drv.sdstr(@FileHeader)                          ' &#9474;  &#9500;&#9472; add header line
          Drv.sdstr(string(" ", 13))                      ' &#9474;  &#9500;&#9472; blank line
          Drv.pclose                                      ' &#9474;  &#9492;&#9472; flush and close the file
                                                          ' &#9474;
        if minit <> minute                                ' &#9500;&#9472; minute changed?
          minit := minute                                 ' &#9474;  &#9500;&#9472; copy the new value
                                                          ' &#9474;  &#9474;
          ifnot (minit // 15)                             ' &#9474;  &#9492;&#9472; every 15 minutes
            Drv.mount(0)                                  ' &#9474;     &#9500;&#9472; mount the disk
            buildDataString                               ' &#9474;     &#9500;&#9472; assemble the log line
            Drv.popen(@fName, "a")                        ' &#9474;     &#9500;&#9472; open the file
            Drv.sdstr(@fData)                             ' &#9474;     &#9500;&#9472; write data
            Drv.pclose                                    ' &#9474;     &#9492;&#9472; flush and close the file
                                                          ' &#9474;
        waitcnt((clkfreq / 2) + cnt)                      ' &#9492;&#9472; wait 1/2 second
            
    
    The code is using the fsrw object (Drv) for writing to the disk. SimplNum is the Simple_Numbers object. Str is the Strings2 object.
    FNAMESIZE = 15; fname is declared as byte fName[FNAMESIZE]. The date and time values are hub variables that are updated from a timekeeping cog.
  • TCP71TCP71 Posts: 38
    edited 2011-06-15 21:20
    Thank you JLocke. I guess I wasn't clear enough on what I was doing. I have the filename that i'm pulling out of a string of characters. The original string is in the format: 06152011.201623.3556432 that is the month/day/year.hour/minute/second.fractionalseconds. From this I pull 06151120.162 and populate my filename array of 12 bytes, "FileName[11]", so that each ascii character is in the array in proper order to create the filename with the period already in the string at its proper location after the first eight digits. Could the problem be that I don't have a 13th place in filename with a 00 (null) in it?

    I then want to create a file on my SD card using FATEngine's function, newFile("06151120.162"). I just don't know how to make each respective Character in the array "FileName" be usable by newFile. It just errors out and wont compile. I can easily create the same file over and over again (eg. newFile("12345678.901") and it will create the file without issue, but I need to populate the actual newFile("XXXXXXXX.XXX") with my array of characters.

    I kind of see how you are filling bytes at @fname with your time and date info. I guess I need to try filling a location of bytes in memory with my file name (06151120.162 in the example above), then point the function "newFile" in the FATEngine object to that location in memory? How does newFile know when to stop looking at the memory locations and the file name is complete. Is that the null character that needs to be at the end of the 8.3 array? I don't have any code in front of me currently, but I don't recall ending the manual file (that has the same file name all the time) with a null character, but I could be wrong.

    The reason I'm using FATEngine and not FSRW is that I need to be able to clear all the files from the card using a simple user interface (I've got that working already, I just reformat the card and it works fine).

    If there is an easier object to use to do this, I'm not stuck on FATEngine. The Fat16/32 full system driver would be fine, but I haven't looked at it. Thanks for all the help.
    JLocke wrote: »
    Here's a logging function I use which automatically updates the filename to be the current date (from a temperature/humidity logger):
    PUB cog_logData | crntDay, minit
      ''* writes current data to SD on schedule (every 15 minutes)
      ''
      ' == cog initialization ==
      waitcnt((clkfreq * 2) + cnt)                        ' wait for date/time to be valid
      ByteFill(@fName, 0, FNAMESIZE)                      ' clear the filename buffer
      
      Str.Concatenate(@fName, SimplNum.decx(year, 2))     ' build the filename
      Str.Concatenate(@fName, string("-"))
      Str.Concatenate(@fName, SimplNum.decx(month, 2))
      Str.Concatenate(@fName, string("-"))
      Str.Concatenate(@fName, SimplNum.decx(day, 2))
      Str.Concatenate(@fName, string(".csv"))             ' save as '.csv' file
    
      Drv.mount(0)                                        ' mount the disk
      Drv.popen(@fName, "a")                              ' open the file
      Drv.sdstr(string("=== REBOOT ===", 13))             ' add indicator line
      Drv.sdstr(@FileHeader)                              ' add header line
      Drv.sdstr(string(" ", 13))                          ' blank line
      Drv.pclose                                          ' flush and close the file  
    
      crntDay := day                                      ' init the triggers
      minit   := minute
    
      ' == cog loop ==
      repeat                                              ' loop
        if crntDay <> day                                 ' &#9500;&#9472; day changed?
          crntDay := day                                  ' &#9474;  &#9500;&#9472; copy the new value
          ByteFill(@fName, 0, FNAMESIZE)                  ' &#9474;  &#9500;&#9472; clear the filename buffer
                                                          ' &#9474;  &#9474;   Build the filename
          Str.Concatenate(@fName, SimplNum.decx(year, 2)) ' &#9474;  &#9500;&#9472;   start with the year
          Str.Concatenate(@fName, string("-"))            ' &#9474;  &#9500;&#9472;   dash -
          Str.Concatenate(@fName, SimplNum.decx(month, 2))' &#9474;  &#9500;&#9472;   month
          Str.Concatenate(@fName, string("-"))            ' &#9474;  &#9500;&#9472;   dash -
          Str.Concatenate(@fName, SimplNum.decx(day, 2))  ' &#9474;  &#9500;&#9472;   day
          Str.Concatenate(@fName, string(".csv"))         ' &#9474;  &#9500;&#9472;   comma-separated values
                                                          ' &#9474;  &#9474;
          Drv.mount(0)                                    ' &#9474;  &#9500;&#9472; mount the disk
          Drv.popen(@fName, "a")                          ' &#9474;  &#9500;&#9472; open the file
          Drv.sdstr(string(" ", 13))                      ' &#9474;  &#9500;&#9472; blank line
          Drv.sdstr(@FileHeader)                          ' &#9474;  &#9500;&#9472; add header line
          Drv.sdstr(string(" ", 13))                      ' &#9474;  &#9500;&#9472; blank line
          Drv.pclose                                      ' &#9474;  &#9492;&#9472; flush and close the file
                                                          ' &#9474;
        if minit <> minute                                ' &#9500;&#9472; minute changed?
          minit := minute                                 ' &#9474;  &#9500;&#9472; copy the new value
                                                          ' &#9474;  &#9474;
          ifnot (minit // 15)                             ' &#9474;  &#9492;&#9472; every 15 minutes
            Drv.mount(0)                                  ' &#9474;     &#9500;&#9472; mount the disk
            buildDataString                               ' &#9474;     &#9500;&#9472; assemble the log line
            Drv.popen(@fName, "a")                        ' &#9474;     &#9500;&#9472; open the file
            Drv.sdstr(@fData)                             ' &#9474;     &#9500;&#9472; write data
            Drv.pclose                                    ' &#9474;     &#9492;&#9472; flush and close the file
                                                          ' &#9474;
        waitcnt((clkfreq / 2) + cnt)                      ' &#9492;&#9472; wait 1/2 second
            
    
    The code is using the fsrw object for writing to the disk. SimplNum is the Simple_Numbers object.
    FNAMESIZE = 15; fname is declared as byte fName[FNAMESIZE]. The date and time values are hub variables that are updated from a timekeeping cog.
  • Mike GreenMike Green Posts: 23,101
    edited 2011-06-15 21:36
    Your STRING("Stuff") supplies the address of the first character of the supplied string and it places the zero byte at the end for you, but the string has to be a constant. If you need to construct the string yourself, you need to supply the address (with @) and put the zero byte at the end yourself.
  • kuronekokuroneko Posts: 3,623
    edited 2011-06-15 21:39
    SPIN does not have a sprintf command...
    This may be overkill (I'm sure it can be cut down for this purpose) but have a look at http://obex.parallax.com/objects/594/.
  • william chanwilliam chan Posts: 1,326
    edited 2011-06-15 21:44
    Thanks Mike, You are a true genius.

    One more question,
    How do I detect the existence of a file in uSD using FATEngine?
  • MacTuxLinMacTuxLin Posts: 821
    edited 2011-06-15 21:46
    I was thinking if one could use the DAT to store the fileName & then change from there?
    DAT
       fileName byte "12345678.TXT", 0
    
    PUB Main
       byte[@fileName][0] := $41   'Change to "A"
       byte[@fileName][1] := $42   "Change to "B"
    
       uSD.newFile(@fileName)
    

    Edit: I tested. It worked.
  • kuronekokuroneko Posts: 3,623
    edited 2011-06-16 02:35
    @MacTuxLin: fileName[0] := "A" will be sufficient (easier to read than byte[@file...).
  • MacTuxLinMacTuxLin Posts: 821
    edited 2011-06-16 02:41
    kuroneko wrote: »
    @MacTuxLin: fileName[0] := "A" will be sufficient (easier to read than byte[@file...).

    Oh, :tongue: ... thanks Kuroneko-san.
  • TCP71TCP71 Posts: 38
    edited 2011-06-16 08:06
    Thanks everyone. I added a null character to the end of the uniquely created filename(13th character), then sent the address of string to the newFile process and the files are being created and written to.

    I appreciate all the help.
  • KyeKye Posts: 2,200
    edited 2011-06-16 09:09
    @william chan - Use the fat.listEntry method to look for a file on the disk... it accepts a path string. If the file doesn't exist the file system will abort and the error code will be loaded into fat.partitionError. Call the fat.partitionError function to get the error code.
Sign In or Register to comment.