Saving state is a problem

So I recently managed to corrupt an SD card without any help from a computer.
Analyzing the problem further leads me to think that the way ProffieOS currently saves state is a problem.

Basically, it comes down to the fact that neither SD cards nor FAT32 were designed with the idea of having the power go out at any time. Every time we rename, delete or create a new file, we are possibly corrupting the directory entries of the SD card.

So what to do?

Well, I think I need to design a new way for ProffieOS to save data on the sd card. This new way would involve creating file on the sd card which is large enough to hold all the data, then figure out a way to save information which never ever directly overwrites the old information. Only information which has been verified as not needed anymore can be overwritten.

Unfortunately, these sort of changes are most likely going to make it harder to edit these save files manually, but I don’t think a lot of people really do that.


wow. So you powered off the board during preset change or something similar?

Yep. I was trying to test the “sd card not found” bug by power-cycling a card a bunch of time, and eventually it turned out corrupted.

Not only did the config file it was saving not work anymore, but the “TeensySF” directory got converted into garble, so all the files in that directory ended up as orphans.

1 Like

Hmm. Sounds like something I’ve experienced for sure. I am certainly one who might be cycling power over and over on occasion. We were blaming Mass Storage + MacOS and caching and…stuff. Maybe it was FAT32’s fault all along.

I’m down to see how this plays out. I’ve only lost one card in all this time but considering what’s said above I think it’s worth the look. Especially as a Mac user.

I had something similar as i was making in hilt changes…the more i power the board on and off the card and files could not be found then power again and they magically appear no issues. SD card failure for my opinion…and more so now than before…

So, here is my current idea for how to deal with this:

  1. Use the same file names as today: filename.ini and filename.tmp
  2. Make the files “large enough” so that we will never need make the file longer.
  3. We reserve the first block (512 bytes) for a magic marker, checksums, length, iteration and other metadata.
  4. When reading, we’ll first read the metadata block of both files. The one that has the higher iteration number is the file we’ll actually use, but only if the checksum is valid.
  5. When writing, we’ll use the other file so that we’re never overwriting the last valid data. First we’ll seek to position 512, then we’ll write the file like normal. Once the data is all written, well update the metadata block with the new checksum, length of the data and the next iteration number.

In terms of performance, writing should actually be faster than what we do today, since we only have to write one file instead of two. Reading will be slower though since we will need to verify the checksum to see if the file is valid or not.

With this method, if writing is interrupted, one file could contain garbage data, but the file structure and the other file should be fine. Interrupted writes could still cause slowdowns and other problems, but they should clear up on the next save.


That sounds like a good plan.

I wouldn’t stress about people not being able to edit manually. If it was never really meant to be done that way in the first place, then at worst, people are losing access to an undocumented feature.

I concur, I think very few ysers will try ir need to edit .ini files by hand. Everytime I was trying to write up documentation for it I realized I would probably co fuse more people than help them and I’d end up scratching most of what I’d written. With the Menu and Workbench available its a very small percentage, if any, who would even attempt to edit manually and that same group would probably be able to continue to edit even with the changes if they were so inclined

1 Like

I seem to recall hearing way back about some kind of SD card file system that was power off safe. Maybe some kind of a journaling files system.

One of the answers there recommends multiple partitions, I think that’s the way to go. Make the main partition with all the data files read only so there’s no chance of corruption. Then create two separate partitions, and write them in round robin fashion. That way one of the partitions is always valid, and the other one may or may not be corrupted.

I wonder if your original idea of essentially managing the contents of files would be thwarted by the wear leveling of an SD card. Even though you’re not allocating new blocks, you might still be writing new blocks.

Last, what about a capacitor backed SD card? Figure out how much time it needs to write that last file, and make sure the capacitor is big enough to let the SD card finish writing on power off.

That article suggests that the problem extends beyond just possibly corrupting the block that is currently being written. However, combined with wear leveling, that would mean that there really isn’t a way to know what blocks will be corrupted if/when power is interrupted, and there would be no way to make it work. (At least not without using capacitors to guard against sudden power loss.)

I’ve written most of the code for the solution I outlined above, so I will try it and see what happens. Obviously, some sd cards might be more stupid than others, but hopefully most of them are not quite as stupid as outlined in the article above.

Btw, using partitions might help, but even then, wear leveling could thwart any efforts. Also, many arduino fat32 implementations don’t let you choose which partition to read/write from, so a solution like that would make it harder to port ProffieOS to new boards.

Will this affect Presets.ini also?

Yes it will.

That’s unfortunate. I commonly use Presets.ini editing for copying and pasting styles as an SD Card-only shortcut. It is faster than plugging saber in to use Workbench, and Edit Mode doesn’t yet allow for ease of font selection in a list of many, nor does it allow for moving preset position in the list.

Just a consideration.

My plan is to have ProffieOS still support regular config files so that if you upgrade while using KEEP_SAVEFILES_WHEN_PROGRAMMING, nothing is lost. A config file with checksums and stuff can easily be cut down to a “regular” config file as long as you text editor can show and delete the extra binary data, so it will still be possible to edit config files manually, but it will require a couple of extra steps.

PS: Workbench allows you to move presets in the list. Should just be a matter of dragging and dropping.

Thanks. I’m referencing editing the presets.ini file. Also, Workbench is great for that, but requires the board to be plugged in. Currently, Presets.ini provides an SD Card-based way to edit preset locations, copy and paste easily, as well as reassign a font or track in seconds.

In short, the Presets.ini is like the “new” Config file we flashed our boards with back in OS 5 and prior. Since OS6, Presets.ini has brought all new nimbleness never before seen to Proffie simply by removing the need to plug the saber in, among many other great things. :wink:

Ok, new state-saving code is checked in on github.
I have tested it but it’s a large-ish change, so the possibility of bugs is not insignificant.
Please give it a try and see how it works and performs.
I don’t think we need to test if it is better for sd corruption or not, I think we can just assume that it is, as long as we assume that when the SD writes are interrupted, they don’t randomly corrupt other parts of the SD card.

It should still be able to read files which don’t have the new format, so if you want to edit files manually you can. To convert a new save file into the old format, you just cut off the first 512 bytes and everything after the first end line. Note that there will be a lot of zeroes and other invisible characters, so you need an editor that can handle and show those characters.

1 Like

I can beat up on it a bit, anything to look for in particular? The expectation is that it performs the same as before for all of the .ini files, correct?