A little fail-safe filesystem designed for microcontrollers (2017)
github.com
github.com
* zero dependencies, no assumptions about libc, doesn't use timers or heap, fully synchronous, and it's passive when you're not interacting with it.
* variables, constants, and functions are well-prefixed (without being too verbose) to avoid collisions.
* BSD license is friendly for single-binary firmwares.
* the Makefile doesn't assume anything, it just outputs a .a file which you can link however you want.
* the Makefile is simple and doesn't require cmake or autotools. it's easy to point it at your cross-compile toolchain.
it has other hallmarks of a well-planned and well-maintained project too:
* the readme shows exactly why i might want this (or might not), and how to use it. the separate design doc shows exactly how it works.
* functionality is cleanly separated by file.
* consistent style (could specify which style guide they're using, though).
* the tests serve their usual purpose but also serve as examples. they're well encapsulated and the code was obviously written to be tested.
these authors have absolutely nailed everything i strive for at my embedded firmware development job.
> variables, constants, and functions are well-prefixed (without being too verbose) to avoid collisions.
Unfortunately it has the same name (Little File System, LFS) and the same function prototypes (lfs_*) of a filesystem for NOR/NAND based systems I did like 10 years ago and still in use, so it will be at least confusing.
As a matter of fact, I guess every embedded technology company using NAND/NOR/whatever memories have their own version of a LFS.
Documentation does look really good. I’ll hang in to this.
It uses c++ for the sake of using c++ instead of leveraging the extreme bonuses c++ provides over using c for embedded. For example, it tends to use dynamic memory allocation heavily, doesn't make use of unique/shared pointer, doesn't use templates properly (if at all) in places it would be ideal (hence increasing code size and slowing things down).
Last I checked, it doesn't support cmake at all, and instead used an extremely complicated and conveluted build system/process.
Both of those combined made me run away and never look back. Another side thing as of late is it seems to be officially supported by arm, which means it will never run on other cores like risc-v. I am not interested in getting stuck with one platform when riscv (in my opinion) has incredible potential for microcontrollers and is seemingly right around the corner.
BTW, you maybe should have mentioned that you work on a competing project.
Over complicating the build system is a reason for dropping almost anything but especially this. The whole point of a framework like that is to make things easier.
That's the one criticism I found valid. I even called it one of the "Four Horsemen of Poor Performance" in a pretty widely read article I wrote on server performance back in 2002. On the other hand, over-reliance on static allocation means allocating many arrays/pools for the worst case, even when they couldn't possibly all hit worst case at the same time, and that can be a pretty bad choice on a highly memory-constrained device. (Doing it for the sake of real-time predictability is actually a different issue.)
OTOH complaining about not using templates because of performance seems exactly backwards, and complaining that it's not likely the the project sponsor will port already-open-source code to a competing architecture themselves seems a bit too entitled. When I see a list of negatives that are mostly bogus, and no mention of positives at all, it's a strong indicator of NIH syndrome.
I have not used it but zephyr (https://www.zephyrproject.org) is a cross platform (including riscv) os/platform that looks interesting for embedded development.
It is confusing though as the code mostly appears to be Apache, not sure if it is just parts that are constrained by the EULA, but it is clearly not intended to be ported to RISC-V or MIPS or whatever.
You don't need any EULA to use any of Mbed's stuff, it's all Apache licensed and can use any compiler.
The official libraries are well-documented and easy to use. I've had to fight a couple vendor-specific oddities when adapting third-party components from their online community, but everything else seem to work as expected.
I remember finding integration with libuv a mite annoying, as mbedTLS is rather pull-minded, and I didn't find the documentation for the I/O callbacks super-clear. If your I/O callbacks are making blocking calls of a pipe or socket, though, I'm sure it's much simpler.
Would use again.
(Would not use OpenSSL again.)
Reminds me of someone using this gif to describe working with OpenSSL.
I would warn anyone to stay away from Cypress/Broadcom's WICED OS which has a modified version of mbedTLS with foolish changes to the API that makes porting code extremely challenging.
Lots of libraries for various sensors and other applications, so if you do early stage development on hardware you can quickly throw prototypes together and not need to deal with sorting through a lot of mediocre Arduino stuff.
YMMV on keeping it for production use. Some parts of it should be fine for some applications. Other things not. I've run into issues with things like threads and timers not always working right for every library, but really that's par for the course on a system of libraries that diverse, and supporting so many different chips.
If you've used this (or are the author) how is the "storage on disk ... always kept in a valid state" feature implemented? Does it write two copies in case a write's interrupted so one can always roll back to the earlier valid copy?
These are single-purpose systems, you don't need to use filenames and have POSIX semantics, you typically just need to put your data into a circular buffer on FLASH. The circular buffer (with checksummed elements) will take care of bad-block management and wear levelling for you.
I've seen this far too often, filesystems are not ideal for this class of system.
As for variable-length configs, yes, but you should always be allocating the worst-case (i.e. defined maximum), hence no need for variable length.