boxlambda icon indicating copy to clipboard operation
boxlambda copied to clipboard

create f_stdout, f_stdin, f_stderr and f_reopen() fatfs extensions

Open epsilon537 opened this issue 4 months ago • 2 comments

Create different 'drives' for SD, serial console, local console, possibly flash. This allows implementation of the extension at media access layer level.

epsilon537 avatar Oct 19 '25 13:10 epsilon537

and remove posix stdin/out from picolibc?

epsilon537 avatar Oct 20 '25 12:10 epsilon537

Or keep picolibc's stdio and using the retargeting api to map to FatFs:

#include "ff.h" // FatFs #include <sys/types.h> #include <sys/stat.h> #include <errno.h> #include <unistd.h>

// Keep track of open files #define MAX_FILES 4 static FIL file_table[MAX_FILES]; static int file_used[MAX_FILES] = {0};

// Convert file descriptor to FIL* static FIL* fd_to_fil(int fd) { if (fd < 0 || fd >= MAX_FILES || !file_used[fd]) return NULL; return &file_table[fd]; }

// Open a file int _open(const char *path, int flags, int mode) { FIL *f = NULL; int fd;

// find a free slot
for (fd = 0; fd < MAX_FILES; fd++) {
    if (!file_used[fd]) {
        f = &file_table[fd];
        file_used[fd] = 1;
        break;
    }
}
if (!f) {
    errno = EMFILE;
    return -1;
}

BYTE fmode = 0;
if (flags & 0x0) fmode = FA_READ;
if (flags & 0x1) fmode = FA_WRITE | FA_CREATE_ALWAYS;

FRESULT res = f_open(f, path, fmode);
if (res != FR_OK) {
    file_used[fd] = 0;
    errno = EIO;
    return -1;
}

return fd;

}

// Close a file int _close(int fd) { FIL *f = fd_to_fil(fd); if (!f) { errno = EBADF; return -1; } f_close(f); file_used[fd] = 0; return 0; }

// Read from a file ssize_t _read(int fd, void *buf, size_t len) { FIL *f = fd_to_fil(fd); if (!f) { errno = EBADF; return -1; } UINT br; FRESULT res = f_read(f, buf, len, &br); if (res != FR_OK) { errno = EIO; return -1; } return br; }

// Write to a file ssize_t _write(int fd, const void *buf, size_t len) { FIL *f = fd_to_fil(fd); if (!f) { errno = EBADF; return -1; } UINT bw; FRESULT res = f_write(f, buf, len, &bw); if (res != FR_OK) { errno = EIO; return -1; } return bw; }

// Seek in a file off_t _lseek(int fd, off_t offset, int whence) { FIL *f = fd_to_fil(fd); if (!f) { errno = EBADF; return -1; }

DWORD newpos;
switch (whence) {
    case SEEK_SET: newpos = offset; break;
    case SEEK_CUR: newpos = f_tell(f) + offset; break;
    case SEEK_END: newpos = f_size(f) + offset; break;
    default: errno = EINVAL; return -1;
}

if (f_lseek(f, newpos) != FR_OK) {
    errno = EIO;
    return -1;
}

return f_tell(f);

}

epsilon537 avatar Oct 20 '25 12:10 epsilon537