Shop OBEX P1 Docs P2 Docs Learn Events
PropGCC SD Card File? — Parallax Forums

PropGCC SD Card File?

SRLMSRLM Posts: 5,045
edited 2013-01-23 23:18 in Propeller 1
I've looked through all the documentation that I can find, but I can't figure out:

How do I get the equivalent functionality to FSRW with PropGCC?

Basically, I want to
- read a list of files in the top level directory
- create a text file and write to it (fast!)

I'd prefer it if it was as close to FSRW in implementation as possible, and lean. I'm not worried about folders (although that would be nice), and I won't be running XMM programs.

Comments

  • RsadeikaRsadeika Posts: 3,837
    edited 2012-12-07 02:47
    How do I get the equivalent functionality to FSRW with PropGCC?
    You could look at filetest.c, which is a Dave Hein product. I have used it, and modified it to some degree to fit some of my requirements; the program works very well, but it only fits in CMM, LMM, or XMMC. You could try using spin2cpp on FSRW, and use the needed functions, I cannot remember if I tried that, so I cannot comment.

    Ray
  • jazzedjazzed Posts: 11,803
    edited 2012-12-07 13:22
    Here's a version of filetest with the monitor files separated.

    Use MONITOR define to reenable the demo. The "abe.txt" demo without the monitor files is about 17KB in CMM.
  • SRLMSRLM Posts: 5,045
    edited 2012-12-09 13:48
    Thanks for sharing that. I tried it out, and it works. Then I tried modifying it, and making it as minimal as I can. Unfortunately, now I get errors: I can't write to the file anymore. Here is the terminal output:
    Terminal ready
    SD Test.
    Starting Errno: 12
    Load and mount SD: done.
    After mount Errno: 12
    Writing to file.
    Couldn't write the file. Errno: 4
    Opening file. 
    Couldn't read the file. Errno: 4
    

    This would seem to indicate that there isn't enough memory, but the downloader only loads 15016 bytes. Here is the main function:
    int main()
    {
        debug.Start(31, 30, 230400);
        debug.Str("SD Test.\n\r");
        debug.Str("Starting Errno: ");
        debug.Dec(errno);
        debug.Str("\r\n");
    
        manual_mount();
    
        debug.Str("After mount Errno: ");
        debug.Dec(errno);
        debug.Str("\r\n");
    
        char buf[80];
        char abe[] = "Everthing you read on the internet is true. - Abraham Lincoln\n";
        int  size = strlen(abe)+1;
    
    
    
    
        debug.Str("Writing to file.\r\n");
        FILE* fp = fopen("abe2.txt", "w");
        if(fp) {
            int32_t count = fwrite(abe, 1, size, fp);
            fclose(fp);
    
            debug.Str("Wrote ");
            debug.Dec(count);
            debug.Str(" number of elements.");
        }
        else
        {
            debug.Str("Couldn't write the file. Errno: ");
            debug.Dec(errno);
            debug.Str("\r\n");
    
        }
    
        debug.Str("Opening file. \r\n");
        fp = fopen("abe2.txt", "r");
        if(fp) {
            fread(buf, 1, 80, fp);
            debug.Str(buf);
            fclose(fp);
        }
        else
        {
            debug.Str("Couldn't read the file. Errno: ");
            debug.Dec(errno);
            debug.Str("\r\n");
        }
    
        return 0;
    }
    
    If I change the fopen("abe2.txt","r") in the main to open abe.txt (an existing text file on the SD card), the read works correctly. So, it appears that I have just two problems:
    1. Why, on the fopen, would errno give an error of 4 ("interrupted system call") instead of a 2 ("no such file or directory") error?
    2. Why doesn't it write to the SD card? I'll mention that this is a micro SD card, without a R/W switch and that the previous version (posted by Jazzed) worked.
  • Dave HeinDave Hein Posts: 6,347
    edited 2012-12-09 15:29
    I don't believe the values of errno are standardized, so error 4 for one C compiler may be different for another C compiler. In the case of PropGCC errno 4 means "no such file or directory". You can use perror() to print out error strings. The error numbers are defined in errno.h, which is located in propgcc/propeller-elf/include.

    errno is changed only when there is an error, so the initial value of 12 may not represent a real error number. You should check the result of the mount to see if it mounted the SD card OK.

    BTW, an errno of 12 is EIO, which is an unspecified file error.
  • SRLMSRLM Posts: 5,045
    edited 2012-12-09 16:02
    The card seems to mount ok: dfs_mount didn't give an error (from the manual_mount function), and if I change the read section to open an existing text file it works.

    I see now where the Propeller specific errno codes are declared (here). I'm curious as to why they don't match the "standard" meaning of the error codes, at least as far as possible (such as this list).

    So, if the error that I get to create the abe2.txt file is no such file or directory, then where am I going wrong? From fopen documentation I'd expect that fopen will create the file.
  • Dave HeinDave Hein Posts: 6,347
    edited 2012-12-09 17:13
    As I said, I don't thing there's a requirement that the errno codes need to match any particular values. It's best not to depend on them being any specific value. You could use their defined symbols, such as EIO, EOK, EEXIST and ENOENT. Or you can use perror() or strerror().

    You fopen should create abe2.txt. I don't do much C++, so maybe there's a problem with that. Have you tried C instead of C++? You can convert the debug prints to printf's.
  • SRLMSRLM Posts: 5,045
    edited 2012-12-09 21:58
    I found the problem: When there is no serial driver in the _driverlist, then the program does not work.

    I assume this is due to PropGCC initializing stdin/out/err behind the scenes, and trying to initialize the SD card as the IO driver.

    I tested my theory by first making a program with just printfs. I compiled with both GCC and G++, and in both C and C++ modes it worked. Then I made a C++ program with a custom serial driver (FFDS1) outputting to pins 2 and 3, which were hooked up to a second Prop Plug. I was able to get this communication, so I removed all the printf statements from my code. The program still worked.

    Finally, I removed the SimpleSerial driver entry in the driver table, along with it's extern declaration. The program no longer worked (as indicated on pins 2 and 3 with the FFDS1 driver).

    I think this is a bug somewhere is the stdio system. Is there anyway where we can force stdin/out/err not to be initialized?
  • ersmithersmith Posts: 6,054
    edited 2012-12-10 04:44
    SRLM wrote: »
    I see now where the Propeller specific errno codes are declared (here). I'm curious as to why they don't match the "standard" meaning of the error codes, at least as far as possible (such as this list).
    There unfortunately is no standard for the error codes -- even POSIX does not specify them. Linux, Windows, and other systems all have different values. I think the ones in the PropGCC library are probably based on the values returned by GEMDOS (the basis for the Atari ST operating system; some of the PropGCC library is based on a public domain library for the Atari ST).

    As Dave said, you have to use either the symbolic values or the strerror() or perror() functions to make sense of the error codes.

    Eric
  • ersmithersmith Posts: 6,054
    edited 2012-12-10 04:54
    SRLM wrote: »
    I found the problem: When there is no serial driver in the _driverlist, then the program does not work.

    I assume this is due to PropGCC initializing stdin/out/err behind the scenes, and trying to initialize the SD card as the IO driver.

    I think this is a bug somewhere is the stdio system. Is there anyway where we can force stdin/out/err not to be initialized?

    I don't think it's a bug, but perhaps it's a surprising feature. It is documented; see for example http://propgcc.googlecode.com/hg/doc/Library.html#drivers:

    The first driver in the list is the "default" driver, and is used to open the stdin, stdout, and stderr FILE descriptors. If you want finer control over how these files are opened, you can either use the freopen function on them at the start of your code, or define a function _InitIO which will set up the file handles.

    So if you don't want stdout/stderr/stdin you can either put a dummy entry as the first entry in the list (like _NullDriver) or else write your own version of _InitIO, which is the constructor function which is called to set up stdio. The source code for _InitIO may be found in lib/stdio/init_io.c, but it's pretty simple:
    /*
     * default _InitIO function to set up stdio, stderr, etc.
     */
    
    #include <driver.h>
    #include <compiler.h>
    #include <sys/thread.h>
    
    /* this does not need to be in the _TLS area, because
     * all threads share stdin
     */
    static unsigned char linebuf[80];
    
    /* initialize I/O */
    _CONSTRUCTOR void
    _InitIO(void)
    {
      /* open stdin */
      __fopen_driver(stdin, _driverlist[0], "", "r");
      /* make it "cooked" input, and give it a decent sized buffer */
      stdin->_flag |= _IOCOOKED;
      stdin->_base = stdin->_ptr = linebuf;
      stdin->_bsiz = sizeof(linebuf);
    
      /* open stdout */
      __fopen_driver(stdout, _driverlist[0], "", "w");
      /* open stderr */
      __fopen_driver(stderr, _driverlist[0], "", "w");
    }
    
  • SRLMSRLM Posts: 5,045
    edited 2012-12-10 16:49
    _NullDriver was exactly what I was l looking for. For others reading this thread, here is the code:
    //Effectively disables stdin/out/err
    extern _Driver _NullDriver;
    extern _Driver _FileDriver;
    _Driver *_driverlist[] =
    {
        &_NullDriver,
        &_FileDriver,
        NULL
    };
    
    For comparison, switching the code from _SimpleSerialDriver to _NullDriver reduced the code from 15744 bytes to 14764 bytes (~1KB) in CMM Os mode . In both cases, there is no printf or anything in the user code that uses the stdin/out/err. I'm also able to use pins 31 and 30 with user C++ code.
  • SRLMSRLM Posts: 5,045
    edited 2012-12-10 16:54
    Is the PropGCC SD drivers really this slow? I tried to emulate the the pwrite test from FSRW, which basically uses the high level interface to the SD card to open a file, write a bunch of bytes to it, and time the duration. Here is my C++ version of that function:
    int32_t pwrite_test()
    {
        debug.Str("How fast can we write using ");
        debug.Str(__PRETTY_FUNCTION__);
        debug.Str("\r\n");
        FILE* fp = fopen("speed.tst", "w");
    
        if(fp == NULL)
        {
            debug.Str("Warning: null fp in function.\r\n");
        }
        int32_t n = 0;
        int32_t i = 2;
        int32_t duration = 0;
        while(duration < maxdur)
        {
            i += i;
            n += i;
            duration -= CNT;
            for(int x = 0; x < i; x++)
            {
                debug.Dec(x);
                debug.Tx('\r');
                debug.Tx('\n');
                fwrite(&Bigbuf, 1, 8192, fp);
            }
            duration += CNT;
        }
        fclose(fp);
        addspeed("PropGCC fwrite", duration, n*8192);
    
    }
    

    With this code, it is noticably slow: 1kB/s slow. The C++ version of FSRW, when running a similar test, writes at 80kB/s or more. Am I missing something?
  • Dave HeinDave Hein Posts: 6,347
    edited 2012-12-10 17:58
    I think there's something wrong your speed measurements. If I copy a 70K file to another file using the filetest program it takes less than 2 seconds. That's 35K/s reading and writing. I ran the filetest program in CMM mode. If I run it in XMMC mode the copy takes about 3 seconds, but that's still at least 23K/s.
  • SRLMSRLM Posts: 5,045
    edited 2012-12-10 18:14
    It sure seems like something should be wrong, based on the speed. But when I watch the terminal, I can see each iteration through the loop with the fwrite in it, and it really does take about 23 seconds to write 32kB. There isn't anything else in the loop to slow it down. So, I'm probably missing something or doing something stupid.

    Terminal Output:
    Terminal ready
    
    
    -----------
    Compile at 18:05:25, Dec 10 2012.
    Everything you read on the internet is true. - Abraham Lincoln
    
    Ready to start pwrite test from main.
    How fast can we write using int32_t pwrite_test()
    0
    1
    2
    3
    PropGCC fwrite 32 kB in 23672 ms at 1 kB/s
    
  • Dave HeinDave Hein Posts: 6,347
    edited 2012-12-10 19:20
    I tried to compile your program but I get a lot of errors. How did you build it? Do you have a makefile or a SIDE file? I wrote a small program that writes 8192 bytes 10 times, and it took 950 msec in XMMC mode. That's about 86K/s.
  • SRLMSRLM Posts: 5,045
    edited 2012-12-10 19:36
    There is a makefile in the zip folder. All those errors that you get ("invalid conversion") are because I used spin2cpp for the FFDS1 object, and it only has intXX_t types. You can get rid of them with the "-fpermissive" flag (it's also in the Makefile).
  • 10Sector10Sector Posts: 3
    edited 2013-01-23 12:21
    Hi all..

    Long time listener, first time caller...

    I put together a S-Ide gcc (plain C, not ++) project with the program assembled from all the bits/comments above, and plain printf's.

    Kind of a combination of everything said in the thread, included the corrected driver order so it doesn't lock up on a printf (that one had me stumped all last night).

    I'm using propgcc as an excuse to finally learn C properly (I think I've taken in about 4 times, and never went further with it). So excuse any wtf's, or why would you do it that ways..

    Cheers, Joe

    sd_test_c.zip
  • jazzedjazzed Posts: 11,803
    edited 2013-01-23 23:18
    @10Sector

    I'll help as time allows. Others will too. WTF's are ok :)

    Thanks.
    --Steve
Sign In or Register to comment.