Device driver mounted to virtual file system (based on FreeRTOS + FAT)

Dear community,

I am looking for a method to expose a device driver through the file system node or partition. The goal is to achieve Linux/udev-like behavior of a device exposed through the file system. In a nut shell, when approached through the ff_open()/ff_read()/ff_write/ioctl - the devices hook functions should get called and should manage state of underlaying device and data flow to/from it.

So far I have found only “Creating a FreeRTOS-Plus-FAT Media Driver” (sorr, as a new user I could not post a link here) description of this functionality which I am struggling to get working. Everything in the FF_RAMDiskInit() revolves around real/existing memory buffer and one of known FATs. FF_Mount() does not mount dummy instance of FF_Disk_t (even with valid IOManager instance attaached to it) and FF_FS_Add() although adding a disk to virtual file system, does not provide working link to registered IOManager read/write callbacks. The partition is to be seen, though. ff_open() of a file on that partition fails (with returned 0-file handler), without aforementioned callbacks ever being called.

Has anybody got this or comprable functionality working (on any hardware or version of FreeRTOS/FAT-library)?

Regards

The big point to remember is that “FreeRTOS” as a kernel, doesn’t HAVE a “filesystem”. The + FAT section defines a file-system like set of routines to be used. It does NOT support the linux like concept of mount points. As I remember, it also assumes that all devices are “FAT” formatted, and drive selection is inside, not outside that assumption, and thus you can’t try to fake some other type of device into that system.

What you really need is a “real” file-system layer to provide that interface, that hooks fat systems inside it, so you can add your more generic I/O system.

Hello @richard-damon

thank you for your response.

As to your remarks:

It does NOT support the linux like concept of mount points.

That much is clear, hence my question :slight_smile:

As I remember, it also assumes that all devices are “FAT” formatted,

Would you be so kind to refer me to the source of this assumption?

What you really need is a “real” file-system layer to provide that interface, that hooks fat systems inside it, so you can add your more generic I/O system.

If I interpret this document correctly (“Creating a FreeRTOS-Plus-FAT Media Driver”), the abstract file system layer is actually in place (see also the nice graph on that page). So the combination of Disk (FF_Disk_t) and IOManager (_FF_IOMAN) abstractions in the “FreeRTOS plus FAT” library constitute the said abstraction and are file system format-independent. Moreover, I assume that was the original intent behind this functionality.

Additionally, there are block read and block write hooks, that can be used/re-defined to customize the behavior of the file system-like contrstructs.

All that being said, I don’t see why it is not possible to represent any given (real or virtual) device through the file system and access it as any block device like in Linux.

Regards

P.S. Apologies for not providing the link to the referred documentation page, as new user I am not allowed to post links.

Remember that the Linux device model is really adapted from Unix, and that is very very ancient. Assuming that any device type can conceptually be looked at via the same basic model might have been sufficient 40+ years ago, but it is not anymore. If you are looking for an embedded OS modelled after the Unix/Linux device/driver model, you may want to look into Zephyr.

FreeRTOS does not have an I/O model - yet - in the history of it, several attempts have been made, but none of those has survived the conceptual stage. There are many reasons for that, someof which make it very clear why and what is so hard about it.

FreeRTOS is basically a portable task scheduler with a few peripheral add-ons. There is nothing wrong with visions to make more of it and extend it by whatever suits the market, but apparently some of it hasn’t happened yet.

The issue is you are looking at the interface from +FAT to the driver, which, as you not is a block level interface, but the interface from user code to +FAT is file based. If you look at FreeRTOS-Plus-FAT Standard and Native APIs - FreeRTOS™ there is no access to the system other than by files.

AT a quick scan through the code, there seems to be hooks for lower level interfaces, but they aren’t listed in the public API, so may be either future features, or old features not documented. In particular look at ff_dev_support.c and the configuration symbol ffconfigDEV_SUPPORT.

As the FreeRTOS documentation notes, this was developed outside FreeRTOS and pulled in as it seems useful, but doesn’t fully meet their design standards. You could perhaps see what needs to be done to make it more useful for your purpose and propose a patch to implement it.

(And, it looks like there is a FF_FS_Add that adds a FILE SYSTEM as a mount point. Something that has been added since I last did much work with it).

Hello @richard-damon

Yes, this is indeed a problem, which allows one device per file system partition with only two callbacks (read and write) and one additional callback for flush (registered by disk instance).

AT a quick scan through the code, there seems to be hooks for lower level interfaces, but they aren’t listed in the public API, so may be either future features, or old features not documented. In particular look at ff_dev_support.c and the configuration symbol ffconfigDEV_SUPPORT.

This looks to me as a cache of 16 (hardcoded, not configurable) memory-mapped files. It does not call any callbacks, so - not a device interface. Source file name is missleading.

(And, it looks like there is a FF_FS_Add that adds a FILE SYSTEM as a mount point. Something that has been added since I last did much work with it).

This only registers your file system in limited (this time configurable) number of mounted partitions.

Thank you for your respose anyways. I will keep digging and update the post if I find some viable solution.

The fixed numbers are common for embedded system, as many design rules prohibit dynamic allocation of resources after starting.

Some of the other limitations seem to be more about being not fully implemented features, or there is code hiding elsewhere (due to lack of documentation) that makes it actually useful.

This is just the nature of open source code that been moved from one source to another.

“Core” FreeRTOS is very well supported. +FAT is in the “Labs” which are admitted to be very much a hit-or-miss adventure.

I use the ff_open()/ff_read()/ff_write interface via the fopencookie FILE stream interface. See:

However, that might be a subset of the functionality you’re looking for. You could take a look at adapting something like GitHub - oyama/pico-vfs: Thin virtual file system for Raspberry Pi Pico · GitHub.

Hello @carlk3

Thank you for your response.

The technique looks promissing, but I have not found custom callbacks being attached to virtal file system of the FreeRTOS plus FAT in your example on GitHub.

How would you approach taht using the fopencookie-based implementation of file access?

The ultimate goal is to have a set of files mounted to the virtual file system (root or directory or even separate volume) and up on read/write access get the respective calback(s) called.

Regards

For those who didn’t know:

+FAT has a very simple provision to represent several “drives” into one tree:

    name      driver
    /         /* SD-card */
    /etc/     /* SD-card */
    /ram/     /* FAT32 disk in SDRAM */
    /flash/   /* read-only flash driver */
    /web/     /* SD-card */

The sub-drives ( /ram /flash ) can indeed be added with e.g.:

pxRAMDisk = FF_RAMDiskInit( "/ram", ucRAMDisk, mainRAM_DISK_SECTORS, mainIO_MANAGER_CACHE_SIZE );

Years ago, while working on FreeRTOS+FAT, I also developed an FTP server for FreeRTOS+TCP. That is why I wanted a file tree with “symbolic” entries like “/ram” and “/flash”.

I tested both +TCP and +FAT by copying the entire Linux source tree from laptop to device and back. Then I would compare the resulting tree.
Also I took out the SD-card and had it thoroughly checked by Linux ( calling fsck.fat ).

It taught me that IPERF is only a performance meter of bulk data. When copying a (source) file tree, there are thousands of very small files. I learned that a file of zero bytes is sent in a zero-byte TCP session.

In another project, I wrote a Linux video driver, and I added some knobs implemented with sysfs:

echo 45 > /sys/class/video/video0/brightness
echo 12 > /sys/class/video/video0/contrast

That made it possible to use the device with human readable ASCII commands and use script language.

I hoped to create the same possibility in +FAT, but ff_devices.[ch] never got developed. It should either be removed or finish it.

But still, +FAT is a nice piece of software. I am not the author, but I did help to make it better.
@FreeRTOS wrote a merciless test that would find every possible bug: ff_stdio_tests_with_cwd.c

+FAT is still “in the labs”. FAT32 is old now and has limitations. But it is still being maintained and updated when necessary.

Yet I use it in many situations: like update web pages in “/web”. Just copy them an press F5 in the browser.
I can update firmware’s for embedded devices by FTP-copying the code to /ram/
Also, I use +FAT for logging measurements and performance data in audio applications.

Which C Library are you using? The most common standard C library for GCC-based embedded development is the Newlib C Library. It provides a system call (syscall) stub mechanism designed for embedded systems. To implement VFS-like behavior, developers must provide custom implementations for low-level “stub” functions, such as _open, _read, and _write, which act as the bridge between the standard C library and your hardware or specific storage media.