178 lines
5.9 KiB
Markdown
178 lines
5.9 KiB
Markdown
# LLFS (Linked List File System)
|
|
|
|
## Introduction
|
|
The llfs filesystem can be generated using the [mkllfs](mkllfs.md) utility.
|
|
The resulting C file encapsulates the filesystem data within a linked list which can be used by the llfs library.
|
|
|
|
As a flat filesystem, llfs lacks support for directories.
|
|
Using the llfs API, information about the files in the filesystem can be retrieved,
|
|
and the files can be read using direct memory access.
|
|
Alternatively, the POSIX file functions can be used.
|
|
But this is more resource intensive, as data must be copied before using it.
|
|
|
|
It's essential to note that the llfs filesystem operates in a read-only mode,
|
|
restricting operations solely to read functions.
|
|
|
|
## Table of contents
|
|
- [Introduction](#introduction)
|
|
- [Table of contents](#table-of-contents)
|
|
- [Initialization](#initialization)
|
|
- [Usage of the llfs API](#usage-of-the-llfs-api)
|
|
- [The `llfs_file_t` struct](#the-llfs_file_t-struct)
|
|
- [Getting a list of files](#getting-a-list-of-files)
|
|
- [Iterator function (not recommended)](#iterator-function-not-recommended)
|
|
- [Reading a file](#reading-a-file)
|
|
- [Getting the number of files](#getting-the-number-of-files)
|
|
- [Using the POSIX file functions](#using-the-posix-file-functions)
|
|
- [Enabling the external loader in STM32CubeIDE](#enabling-the-external-loader-in-stm32cubeide)
|
|
|
|
## Initialization
|
|
Before using the llfs API, or the file related POSIX (fopen, fgetc, ...) functions, the filesystem must be initialized by calling `llfs_init()`.
|
|
|
|
## Usage of the llfs API
|
|
### The `llfs_file_t` struct
|
|
The `llfs_file_t` struct contains information about a file in the filesystem.
|
|
```c
|
|
typedef struct {
|
|
const uint8_t* data; // Pointer to the file data (len bytes)
|
|
const char* name; // Null-terminated string with the filename
|
|
size_t len; // Length of the file data
|
|
} llfs_file_t;
|
|
```
|
|
The data pointer points to the data of the file in the filesystem, and can be used to read the file.
|
|
|
|
### Getting a list of files
|
|
```c
|
|
#include "llfs.h"
|
|
|
|
void main(void) {
|
|
llfs_init();
|
|
|
|
// Allocate space for 10 files
|
|
llfs_file_t file_list[10];
|
|
|
|
// Get the file list
|
|
size_t file_count = llfs_file_list(file_list, 10, NULL);
|
|
|
|
// Loop through the files and print their names and sizes
|
|
for (int i = 0; i < file_count; i++) {
|
|
LOG_INFO(TAG, "File: %s, size: %d", file_list[i].name, file_list[i].len);
|
|
}
|
|
}
|
|
```
|
|
Result:
|
|
```
|
|
[Info] (2009) [main]: File: image.bmp, size: 9270
|
|
[Info] (2013) [main]: File: python_file.py, size: 645
|
|
[Info] (2019) [main]: File: image2.bmp, size: 7738
|
|
[Info] (2024) [main]: File: filename with a space.txt, size: 61
|
|
[Info] (2031) [main]: File: file1.txt, size: 77
|
|
```
|
|
|
|
It is also possible to use a file extension filter (e.g. `*.bmp`, `*.txt`, `*.py`).
|
|
```c
|
|
// ...
|
|
size_t file_count = llfs_file_list(file_list, 10, "*.bmp");
|
|
// ...
|
|
```
|
|
This will only return files with the `.bmp` extension.
|
|
````
|
|
[Info] (2009) [main]: File: image.bmp, size: 9270
|
|
[Info] (2019) [main]: File: image2.bmp, size: 7738
|
|
````
|
|
|
|
#### Iterator function (not recommended)
|
|
It is also possible to iterate through the files without allocating an array.
|
|
When the memory pointer is `NULL`, the iterator will start at the beginning of the file list.
|
|
Each call to `llfs_next_file()` will return the next file in the list,
|
|
if a filter is specified files that don't match the filter will be skipped.
|
|
```c
|
|
#include "llfs.h"
|
|
|
|
void main(void) {
|
|
llfs_init();
|
|
|
|
// Get the file list
|
|
void* mem = NULL; // Pointer for internal use by the llfs library
|
|
llfs_file_t* file;
|
|
while ((file = llfs_next_file(&mem, ".bmp")) != NULL) {
|
|
LOG_INFO(TAG, "File: %s", file->name);
|
|
}
|
|
}
|
|
```
|
|
While this method doesn't require allocating memory for the file list,
|
|
it is slower than the previous method due to the overhead calling the function for each file.
|
|
Additionally, the required memory for the filelist is very small, so it's recommended to use the first method.
|
|
|
|
### Reading a file
|
|
```c
|
|
#include "llfs.h"
|
|
|
|
void main(void) {
|
|
llfs_init();
|
|
|
|
// Get a file by name
|
|
llfs_file_t* file = llfs_file_open("filename with a space.txt");
|
|
|
|
if (file != NULL) {
|
|
// Print the file name, size and data
|
|
LOG_INFO(TAG, "File found: %s, size: %d", file->name, file->len);
|
|
LOG_INFO(TAG, "File data: %s", file->data);
|
|
} else {
|
|
LOG_WARN(TAG, "File not found");
|
|
}
|
|
}
|
|
```
|
|
Result:
|
|
```
|
|
[Info] (2040) [main]: File found: filename with a space.txt, size: 61
|
|
[Info] (2047) [main]: File data: This is a file with a space in it's filename.
|
|
```
|
|
|
|
### Getting the number of files
|
|
```c
|
|
#include "llfs.h"
|
|
|
|
void main(void) {
|
|
llfs_init();
|
|
|
|
// Get the number of files
|
|
size_t file_count = llfs_file_count();
|
|
|
|
// Print the number of files
|
|
LOG_INFO(TAG, "File count: %d", file_count);
|
|
}
|
|
```
|
|
|
|
## Using the POSIX file functions
|
|
The llfs library also supports the POSIX file functions.
|
|
As the file system is read-only, write functions are not implemented.
|
|
There is also a limit on the number of files that can be open concurrently,
|
|
this is set by the `POSIX_MAX_FILES` macro in `llfs.c`.
|
|
The default value is 10, but there are already 3 files in use (stdin, stdout, stderr),
|
|
so the maximum number of files that can be open is 7.
|
|
|
|
The following functions are tested and working, but other functions might also work:
|
|
- `fopen`
|
|
- `fclose`
|
|
- `fgetc`
|
|
- `fread`
|
|
- `fseek`
|
|
- `ftell`
|
|
- `rewind`
|
|
- `fstat`
|
|
- `fileno`
|
|
|
|
## Enabling the external loader in STM32CubeIDE
|
|
In order to write the file system data to the QSPI flash, the external loader must be enabled in STM32CubeIDE.
|
|
This can be done by opening the debug configuration:
|
|
|
|

|
|
|
|
Then, in the `Debugger` tab:
|
|
3. Enable the `External Loader`
|
|
4. Click the `Scan` button
|
|
5. Select the correct loader: `N25Q128A_STM32F746G-DISCO, 0x90000000 ...`
|
|
|
|

|