8 years, 8 months ago.

std::fopen() returns NULL for Stream class in Arduino Due port.

Hi,

This is a pretty hardcore questions, so if this isn't the place for it I'd appreciate being pointed in the right direction!

Ok, so I'm porting the Arduino Due to the mBed API (since the Arduino one is awful). I've written Serial implementation but when testing it out it doesn't work. I've narrowed the problem down to this code:

Stream::Stream(const char *name) : FileLike(name), _file(NULL) {
    /* open ourselves */
    char buf[12]; /* :0x12345678 + null byte */
	std::sprintf(buf, ":%p", this);
	_file = std::fopen(buf, "w+");
	mbed_set_unbuffered_stream(_file);
}

Basically, std::fopen() returns null, and then mbed_set_unbuffered_stream() calls setbuf(NULL, NULL) which crashes.

I don't have the source for std::fopen (and I'm actually debugging via a single LED; I don't have GDB set up), however I believe it works by calling _open() in retarget.cpp:

extern "C" FILEHANDLE PREFIX(_open)(const char* name, int openmode) {
    #if defined(__MICROLIB) && (__ARMCC_VERSION>5030000)
    // Before version 5.03, we were using a patched version of microlib with proper names
    // This is the workaround that the microlib author suggested us
    static int n = 0;
    if (!std::strcmp(name, ":tt")) return n++;

    #else
    /* Use the posix convention that stdin,out,err are filehandles 0,1,2.
     */
    if (std::strcmp(name, __stdin_name) == 0) {
        init_serial();
        return 0;
    } else if (std::strcmp(name, __stdout_name) == 0) {
        init_serial();
        return 1;
    } else if (std::strcmp(name, __stderr_name) == 0) {
        init_serial();
        return 2;
    }
    #endif

    // find the first empty slot in filehandles
    unsigned int fh_i;
    for (fh_i = 0; fh_i < sizeof(filehandles)/sizeof(*filehandles); fh_i++) {
        if (filehandles[fh_i] == NULL) break;
    }
    if (fh_i >= sizeof(filehandles)/sizeof(*filehandles)) {
        return -1;
    }

    FileHandle *res;

    /* FILENAME: ":0x12345678" describes a FileLike* */
    if (name[0] == ':') {
        void *p;
        sscanf(name, ":%p", &p);
        res = (FileHandle*)p;

    /* FILENAME: "/file_system/file_name" */
    } else {
        FilePath path(name);

        if (!path.exists())
            return -1;
        else if (path.isFile()) {
            res = path.file();
        } else {
            FileSystemLike *fs = path.fileSystem();
            if (fs == NULL) return -1;
            int posix_mode = openmode_to_posix(openmode);
            res = fs->open(path.fileName(), posix_mode); /* NULL if fails */
        }
    }

    if (res == NULL) return -1;
    filehandles[fh_i] = res;

    return fh_i + 3; // +3 as filehandles 0-2 are stdin/out/err
}

As you can see, it checks that the filename is something like ":0x12345678" and if it is it should return 3 on the first call. I verified that it does by calling it manually.

So my question is: if _open(...) returns 3 as it should, why does std::fopen() return NULL? And why does it work for other targets?

Edit: Actually I added LED flashing code to the top of _open() and it seems like it doesn't even get there. So now I'm at a total loss.

Hello,

you using ARMCC (in uvision IDE) ? Did you check you got your stack and heap properly set?

posted by Martin Kojtal 02 Sep 2015

I'm using GCC via with QBS (a build system). I think I've got it set right. I basically copied all the settings from the Makefiles in the Atmel SDK.

posted by Tim H 02 Sep 2015
Be the first to answer this question.