The NiFAT32 project is FAT32 file system with a modification which improves overall performance under SEU (Single Event Upset) and MEU (Multiple Event Upsets). This project can be used as a library, as an independent executable and as a system for an IoT device.
To load a NiFAT32 instance you will need to invoke the NIFAT32_init() function with boot parameters:
nifat32_params_t params;
if (!NIFAT32_init(¶ms)) {
return EXIT_FAILURE;
}Parameters are the next:
| Parameter | Full name | Possible values |
|---|---|---|
| fat_cache | Status for the FAT cache system | NO_CACHE (There is no FAT cache), CACHE (There is a classic 'lazy' (on load) cache), CACHE + HARD_CACHE (There is a cache which will load entire table at the start) |
| bs_num | Boot sectors number (Service field, do not change) | 0 |
| bs_count | Boot sectors count | >= 1 |
| ts | Total sectors count in the image (You can get this value by dividing the total size of the image in bytes with the sector size in bytes) | >= 1 |
| jc | Journal sectors count | >= 0 |
| ec | Error storage sectors count | >= 0 |
| disk_io | Disk IO function pointers | - |
| logg_io | Logging IO function pointers | - |
NiFAT32 names directories and files as content entries. To open an existed content you will need to invoke the NIFAT32_open_content function with the root_ci parameter (Can be NO_RCI) which represents the content index where we're searching the content (If it receives the NO_RCI value, it will search in the entire image). Also you will need to get a name of the target content (or a path) and set a mode. There are several modes in the system:
| Parameter | Description |
|---|---|
| DF_MODE | Will open a content in Read + Write mode |
| R_MODE | Will open a content only in Read mode |
| W_MODE | Will open a content only in Write mode |
| CR_MODE | Will tell to the system that we need to create all content entries that don't exist. This mode is used with NO_TARGET, FILE_TARGET and DIR_TARGET options. This will say which type is the last part in the path ('cause we can't say there is a directory or a file at the path's tale). |
Let's open the hello.txt that is present in the dir directory. To accomplish this, we can either use the full path, or open the directory first. The second approach is usefull if a directory is placed deep in the file system, and we use it really often.
ci_t ci = NIFAT32_open_content(NO_RCI, "DIR/HELLO TXT", MODE(R_MODE, NO_TARGET)); // The last name in the path *must* be in the 8.3 format! Use in-built helpers to achive this.
if (ci >= 0) {
// The target file (Read-only) is opened with the `ci` index.
}To create a new content entry, you will need to use the NIFAT32_put_content. This function accepts the root_ci (Root content index, something like the file descriptor), content information (see the table below), and reserce cluster count.
Content information is a structure that is presented below:
| Parameter | Full name | Possible values |
|---|---|---|
| full_name | All 11 characters (Name + Extention) | A string from 0 bytes length to 11 bytes length. |
| name | First 8 bytes from the name (Optional for creation) | A string from 0 bytes length to 8 bytes length. |
| extention | Last 3 bytes from the name (Optional for creation) | A string from 0 bytes length to 3 bytes length. |
| size | Content size (For directories always 0) | >= 0 |
| type | Content entry type | STAT_FILE - content is a file STAT_DIR - content is a directory |
The root_ci value sets the destination where the new content will be stored. If there is no directories in the file system instance, this value can be obtained from the opn function with NO_RCI. For instance let's make a new directory in an empty file system instance:
ci_t rci = NIFAT32_open_content(NO_RCI, NULL, MODE(W_MODE, NO_TARGET));
if (rci >= 0) {
cinfo_t info = { .type = STAT_DIR, .full_name = "TDIR " };
NIFAT32_put_content(rci, &info, NO_RESERVE);
NIFAT32_close_content(rci);
}There is a less complex way of how to create a file or a directory. The NIFAT32_open_content as it mentioned above can create all non-existed files/directories with the CR_MODE flag. In a nutshell the code above can be re-written:
ci_t new_directory = NIFAT32_open_content(NO_RCI, "TDIR ", MODE(CR_MODE | R_MODE | W_MODE, DIR_TARGET));
if (new_directory >= 0) {
// The directory is created and opened with the `new_directory` index.
}P.S.: One flaw in the second approach is that we can't set the reserved count of clusters. The NIFAT32_put_content function can pre-allocate a chain for data which can help with de-fragmentation in future.
To perform this operation you will need to invoke the NIFAT32_change_meta function which accepts the ci of the target content and a new information (cinfo_t). Let's rename the directory above and change its type to file.
// ci_t new_directory = ...
cinfo_t info = { .type = STAT_DIR, .full_name = "TFILE TXT", .size = 1, .type = STAT_FILE };
NIFAT32_change_meta(new_directory, &info);To write a data to a content entry, you need to use the NIFAT32_write_buffer2content function which accepts the content index of a content entry, offset, the data and size of the data.
// ci_t new_directory = ... (now this is tfile.txt)
if (NIFAT32_write_buffer2content(new_directory, 0, "Hello world!", 12) == 12) {
}To read a data from a content entry, you need to use the NIFAT32_read_content2buffer function which accepts the content index of a content entry, offset, the output buffer and size of the output buffer.
char buffer[64];
// ci_t new_directory = ... (now this is tfile.txt)
if (NIFAT32_write_buffer2content(new_directory, 0, buffer, sizeof(buffer)) == 12) {
}The NiFAT32 file system can create a shallow copy of a content or a deep copy. The shallow copy addresses the problem of backup meta information in terms of SEU presents, that's why I strongly suggest to use it for your files if your system will encounter SEU. To perform this you will need to invoke the NIFAT32_copy_content which accepts target and source content indexes (You will need to create a dummy placeholder for a copy) and copy type (DEEP_COPY or SHALLOW_COPY).
// ci_t new_directory = ... (now this is tfile.txt)
ci_t copy = NIFAT32_open_content(NO_RCI, "TDIR ", MODE(CR_MODE | R_MODE | W_MODE, DIR_TARGET));
if (copy >= 0) {
NIFAT32_copy_content(new_directory, copy, SHALLOW_COPY);
NIFAT32_close_content(copy);
}To delete a content entry (and erase all data, which means delete data in files and delete files and directories recursively in directories) you will need to use the NIFAT32_delete_content function. This function accepts only one parameter - content index.
// ci_t new_directory = ... (now this is tfile.txt)
NIFAT32_delete_content(copy);
NIFAT32_delete_content(new_directory);