Skip to content

tanakamasayuki/EmbedFS

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

EmbedFS

EmbedFS is a tiny, read-only virtual filesystem intended for Arduino and ESP32 projects. It lets you embed files (assets) directly in flash (program memory) as const data and access them through a filesystem-like API compatible with common Arduino FS libraries (SD, SPIFFS, LittleFS). Use this when you want to ship static assets with your firmware and avoid runtime copying or external storage.

Key features

  • Read-only virtual filesystem implemented as arrays in flash (const data).
  • Provides Arduino File/FS style operations (open, read, exists, openNextFile, rewindDirectory, etc.).
  • Directories can be opened and iterated, so hierarchical layouts work as expected.
  • Designed for ESP32 and other Arduino-compatible boards.
  • Works with assets generated by the Arduino CLI Wrapper (assets_embed.h) or any tool that converts a directory into a C header with a file index and byte arrays.
  • No runtime writes — ideal for firmware-embedded resources.

Intended usage

  1. Convert your assets/ folder to a C header (for example assets_embed.h) using the Arduino CLI Wrapper or another conversion tool. The generated header should expose the embedded data and an index that the library can consume (for example: pointers to file data, lengths, and names).
  2. Include assets_embed.h in your sketch and initialize EmbedFS with the generated data.
  3. Use the same familiar FS-like calls to open and read files.

The example sketch in examples/BasicTest/ initializes EmbedFS like this:

EmbedFS.begin(assets_file_names, assets_file_data, assets_file_sizes, assets_file_count);

So the generated header used by that example exposes these symbols (names and types):

  • constexpr size_t assets_file_count — number of embedded files
  • const char* const assets_file_names[assets_file_count] — array of file paths (C strings)
  • const uint8_t* const assets_file_data[assets_file_count] — array of pointers to file bytes (PROGMEM/const)
  • const size_t assets_file_sizes[assets_file_count] — array of file sizes

The library begin() call in that sketch expects the arrays above. The header generated by Arduino CLI Wrapper is PROGMEM-friendly (values stored with PROGMEM if available) and uses C-style arrays so they can be passed directly to begin().

Note: The library is read-only. It is not a replacement for writable filesystems like SD or LittleFS when you need persistence or runtime file updates.

Example (Arduino / ESP32)

The code below mirrors examples/BasicTest/BasicTest.ino. The generated header (assets_embed.h) is assumed to provide the arrays described above.

#include <EmbedFS.h>
#include "assets_embed.h"

void setup() {
  Serial.begin(115200);
  delay(1000);

  if (!EmbedFS.begin(assets_file_names, assets_file_data, assets_file_sizes, assets_file_count)) {
    Serial.println("EmbedFS mount failed");
    return;
  }

  Serial.println("Embedded files:");
  for (size_t i = 0; i < assets_file_count; ++i) {
    File file = EmbedFS.open(assets_file_names[i], "r");
    if (!file) {
      continue;
    }
    Serial.printf("- path: %s size: %u bytes\n", file.path(), static_cast<unsigned>(file.size()));
    while (file.available()) {
      Serial.write(file.read());
    }
    Serial.println();
    file.close();
  }

  Serial.println("Directory listing of /directory:");
  File dir = EmbedFS.open("/directory");
  if (dir && dir.isDirectory()) {
    dir.rewindDirectory();
    while (true) {
      File child = dir.openNextFile();
      if (!child) {
        break;
      }
      Serial.printf("- %s (%s)\n", child.path(), child.isDirectory() ? "dir" : "file");
      child.close();
    }
    dir.close();
  }
}

void loop() {
  delay(10000);
}

BasicTest repeats the dump every 10 seconds so you can watch file contents and /directory children on the serial monitor.

API contract (recommended)

To be a convenient drop-in for Arduino projects, the EmbedFS library typically offers the following minimal contract:

  • bool begin(const char* const file_names[], const uint8_t* const file_data[], const size_t file_sizes[], size_t file_count)
    • Initialize the library with the generated arrays (file names, data pointers, sizes and count).
  • File open(const char* path, const char* mode = "r")
    • Open a file in read mode ("r"). The returned File supports read(), available(), size(), path() and name(). When the target is a directory, isDirectory() returns true and you can iterate children via openNextFile() / rewindDirectory().
  • bool exists(const char* path)
    • Return true if an embedded file or directory with that path exists.
  • size_t totalBytes() / size_t usedBytes()
    • Return the total embedded byte count (identical for read-only storage).

Error modes:

  • begin() returns false on invalid index pointers or zero count.
  • open() returns a falsy File when the target path is missing or the mode is unsupported.

Design note: keep the API read-only. If you need write support, use SD or LittleFS.

Class shape recommendation (FS-like)

To be familiar to users, EmbedFS mirrors LittleFS and exposes a global instance. The implementation is shaped like this:

class EmbedFSFS : public FS {
public:
  bool begin(const char* const file_names[], const uint8_t* const file_data[], const size_t file_sizes[], size_t file_count);
  bool begin(bool formatOnFail = false, const char* basePath = "/embedfs", uint8_t maxOpenFiles = 10, const char* partitionLabel = nullptr);
  bool exists(const char* path) const;
  File open(const char* path, const char* mode = "r") const;
  void end();
  size_t totalBytes();
  size_t usedBytes();
};

extern EmbedFSFS EmbedFS;

examples/BasicTest/ calls EmbedFS.begin(assets_file_names, assets_file_data, assets_file_sizes, assets_file_count);, streams text directly from the returned File, and opens /directory to iterate children with openNextFile().

How to generate assets_embed.h

Preferred: Arduino CLI Wrapper (the project that converts assets/ to assets_embed.h). It typically produces a header that contains the file data and an index table. The details depend on the tool, but a minimal layout is:

  • an array (or arrays) with file bytes stored in PROGMEM/const
  • a struct array with entries: { const char* path; const uint8_t* data; size_t length }
  • a symbol with count/size

If you don't use Arduino CLI Wrapper, you can prepare a similar header with a script. Example (Python) to generate a simple header (illustrative only):

#!/usr/bin/env python3
import sys
from pathlib import Path

out = []
files = list(Path('assets').rglob('*'))

for p in files:
    if p.is_file():
        name = '/' + str(p.relative_to('assets')).replace('\\', '/')
        b = p.read_bytes()
        arr = ','.join(str(x) for x in b)
        out.append(f"// {name}\nstatic const uint8_t data_{len(out)}[] PROGMEM = {{{arr}}};\n")

print('\n'.join(out))

You must also produce the index entry mapping paths to data arrays. The exact layout depends on how EmbedFS::begin() expects the input.

Examples folder

See examples/BasicTest/ in this repository for a minimal Arduino sketch and an example assets_embed.h produced by the Arduino CLI Wrapper. That example shows the expected header format and demonstrates directory iteration.

Limitations and edge cases

  • Read-only: files cannot be modified at runtime.
  • Flash-size: embedded assets are stored in program memory; be mindful of flash usage on small MCUs.
  • Path normalization: generated index should use a consistent path format (leading slash vs. not). EmbedFS should normalize paths internally.
  • Binary files: reading binary data works the same as text; take care when printing to Serial (use write rather than print for binary blobs).

Performance

  • Accessing data stored in flash (PROGMEM) is fast and avoids SD card latency.
  • Memory usage: EmbedFS should avoid copying whole files into RAM; provide a File stream abstraction that reads directly from flash.

Contributing

Contributions are welcome. When opening an issue or PR, please include:

  • A short description of the use case.
  • Minimal reproduction (board, Arduino core version, a small sketch and assets).

License

This repository follows the license in the project root (see LICENSE).

Troubleshooting

  • If begin() fails: check that the generated header symbols are present and the index format matches what EmbedFS expects.
  • If files are not found: verify the path used by the sketch matches the path in the generated index (leading /, case sensitivity, directory separators).

Summary

EmbedFS provides a small, convenient way to bundle static assets into your firmware and access them via a familiar filesystem-like API. It is especially useful for small web assets, configuration templates, or resources that never change at runtime.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors