initial commit

This commit is contained in:
feeling001@gmail.com
2026-06-08 14:33:53 +02:00
commit a7eb474a97
8 changed files with 686 additions and 0 deletions
+328
View File
@@ -0,0 +1,328 @@
/**
* @file main.cpp
* @brief Test verbeux LittleFS sur ESP32-S3
*
* Séquence de tests :
* 1. Montage du système de fichiers LittleFS
* 2. Affichage des infos de la partition (total / utilisé / libre)
* 3. Écriture d'un fichier texte
* 4. Relecture et vérification du contenu
* 5. Écriture binaire (tableau d'octets)
* 6. Relecture binaire et vérification byte-à-byte
* 7. Listage du répertoire racine
* 8. Test d'append (ajout à un fichier existant)
* 9. Renommage de fichier
* 10. Suppression de tous les fichiers de test
* 11. Vérification de la suppression
* 12. Démontage propre
* 13. Résumé PASS / FAIL
*/
#include <Arduino.h>
#include <LittleFS.h>
// ──────────────────────────────────────────────────────────────
// Macros de log colorées (ANSI visible dans un terminal VT100)
// ──────────────────────────────────────────────────────────────
#define CLR_RESET "\033[0m"
#define CLR_GREEN "\033[32m"
#define CLR_RED "\033[31m"
#define CLR_CYAN "\033[36m"
#define CLR_YELLOW "\033[33m"
#define CLR_BOLD "\033[1m"
#define LOG_INFO(fmt, ...) Serial.printf(" [INFO] " fmt "\r\n", ##__VA_ARGS__)
#define LOG_OK(fmt, ...) Serial.printf(CLR_GREEN " [ OK ] " fmt CLR_RESET "\r\n", ##__VA_ARGS__)
#define LOG_FAIL(fmt, ...) Serial.printf(CLR_RED " [FAIL] " fmt CLR_RESET "\r\n", ##__VA_ARGS__)
#define LOG_STEP(n, fmt, ...) \
Serial.printf(CLR_CYAN CLR_BOLD "\n── Étape %d : " fmt CLR_RESET "\r\n", n, ##__VA_ARGS__)
#define LOG_WARN(fmt, ...) Serial.printf(CLR_YELLOW " [WARN] " fmt CLR_RESET "\r\n", ##__VA_ARGS__)
// ──────────────────────────────────────────────────────────────
// Noms des fichiers de test
// IMPORTANT : ne pas utiliser FILE_WRITE / FILE_READ / FILE_APPEND
// comme noms de variables — ce sont des macros définies dans FS.h
// ("w", "r", "a"). On préfixe avec TEST_ pour éviter le conflit.
// ──────────────────────────────────────────────────────────────
static const char* TEST_FILE_TEXT = "/test_text.txt";
static const char* TEST_FILE_BIN = "/test_binary.bin";
static const char* TEST_FILE_APPEND = "/test_append.txt";
static const char* TEST_FILE_RENAMED = "/test_renamed.txt";
// ──────────────────────────────────────────────────────────────
// Compteurs globaux de tests
// ──────────────────────────────────────────────────────────────
static uint32_t g_pass = 0;
static uint32_t g_fail = 0;
// ──────────────────────────────────────────────────────────────
// Helpers
// ──────────────────────────────────────────────────────────────
static void check(bool condition, const char* label)
{
if (condition) {
LOG_OK("%s", label);
g_pass++;
} else {
LOG_FAIL("%s", label);
g_fail++;
}
}
/** Liste récursive d'un répertoire */
static void listDir(const char* path, uint8_t depth = 0)
{
File root = LittleFS.open(path);
if (!root || !root.isDirectory()) {
LOG_WARN("Impossible d'ouvrir le répertoire : %s", path);
return;
}
File entry = root.openNextFile();
while (entry) {
for (uint8_t i = 0; i < depth; i++) Serial.print(" ");
if (entry.isDirectory()) {
Serial.printf(" [DIR] %s\r\n", entry.name());
listDir(entry.path(), depth + 1);
} else {
Serial.printf(" [FIL] %-30s %6lu octets\r\n",
entry.name(), (unsigned long)entry.size());
}
entry = root.openNextFile();
}
}
/** Supprime un fichier et log le résultat */
static void removeFile(const char* path)
{
if (LittleFS.exists(path)) {
bool ok = LittleFS.remove(path);
LOG_INFO("Suppression de %s -> %s", path, ok ? "succes" : "ERREUR");
check(ok, String(String("remove(") + path + ")").c_str());
} else {
LOG_WARN("Fichier absent (skip remove) : %s", path);
}
}
// ──────────────────────────────────────────────────────────────
// setup()
// ──────────────────────────────────────────────────────────────
void setup()
{
Serial.begin(115200);
delay(2000); // Laisse le temps à l'hôte de s'connecter
Serial.println();
Serial.println(CLR_BOLD "╔════════════════════════════════════════╗" CLR_RESET);
Serial.println(CLR_BOLD "║ TEST LittleFS ESP32-S3 ║" CLR_RESET);
Serial.println(CLR_BOLD "╚════════════════════════════════════════╝" CLR_RESET);
Serial.printf(" Compilé le : %s %s\r\n", __DATE__, __TIME__);
Serial.printf(" CPU Freq : %u MHz\r\n", (unsigned)(ESP.getCpuFreqMHz()));
Serial.printf(" Flash size : %u MB\r\n", (unsigned)(ESP.getFlashChipSize() / (1024*1024)));
Serial.printf(" Free heap : %u octets\r\n", (unsigned)ESP.getFreeHeap());
// ── Étape 1 : Montage ───────────────────────────────────────
LOG_STEP(1, "Montage de LittleFS");
bool mounted = LittleFS.begin(true); // true = formater si nécessaire
check(mounted, "LittleFS.begin()");
if (!mounted) {
LOG_FAIL("Abandon : impossible de monter LittleFS");
return;
}
// ── Étape 2 : Informations de la partition ───────────────────
LOG_STEP(2, "Informations de la partition");
size_t total = LittleFS.totalBytes();
size_t used = LittleFS.usedBytes();
size_t free_ = total - used;
LOG_INFO("Taille totale : %7u octets (%u KB)", (unsigned)total, (unsigned)(total/1024));
LOG_INFO("Utilisé : %7u octets (%u KB)", (unsigned)used, (unsigned)(used /1024));
LOG_INFO("Libre : %7u octets (%u KB)", (unsigned)free_, (unsigned)(free_/1024));
check(total > 0, "Partition non nulle");
// ── Étape 3 : Écriture texte ─────────────────────────────────
LOG_STEP(3, "Ecriture d'un fichier texte");
const char* textContent =
"Ligne 1 : Hello from LittleFS!\n"
"Ligne 2 : ESP32-S3 test ecriture / lecture.\n"
"Ligne 3 : Caracteres speciaux : eaü\n"
"Ligne 4 : Fin du fichier texte.\n";
{
File f = LittleFS.open(TEST_FILE_TEXT, "w"); // "w" = FILE_WRITE
check(f, "open(\"w\") - fichier texte");
if (f) {
size_t written = f.print(textContent);
LOG_INFO("Octets ecrits : %u / %u", (unsigned)written, (unsigned)strlen(textContent));
check(written == strlen(textContent), "Nombre d'octets ecrits correct");
f.close();
LOG_INFO("Fichier ferme : %s", TEST_FILE_TEXT);
}
}
// ── Étape 4 : Relecture et vérification texte ────────────────
LOG_STEP(4, "Relecture et verification du fichier texte");
{
File f = LittleFS.open(TEST_FILE_TEXT, "r"); // "r" = FILE_READ
check(f, "open(\"r\") - fichier texte");
if (f) {
String readBack = f.readString();
f.close();
LOG_INFO("Octets relus : %u", (unsigned)readBack.length());
bool match = (readBack == String(textContent));
check(match, "Contenu texte identique (round-trip)");
if (!match) {
LOG_FAIL("--- Attendu ---");
Serial.println(textContent);
LOG_FAIL("--- Obtenu ---");
Serial.println(readBack);
} else {
LOG_INFO("Apercu contenu :");
int lineCount = 0;
for (char c : readBack) {
Serial.print(c);
if (c == '\n' && ++lineCount >= 2) break;
}
Serial.println();
}
}
}
// ── Étape 5 : Écriture binaire ───────────────────────────────
LOG_STEP(5, "Ecriture d'un fichier binaire (256 octets)");
uint8_t binData[256];
for (int i = 0; i < 256; i++) binData[i] = (uint8_t)i; // 0x00 … 0xFF
{
File f = LittleFS.open(TEST_FILE_BIN, "w"); // "w" = FILE_WRITE
check(f, "open(\"w\") - fichier binaire");
if (f) {
size_t written = f.write(binData, sizeof(binData));
LOG_INFO("Octets ecrits : %u / %u", (unsigned)written, (unsigned)sizeof(binData));
check(written == sizeof(binData), "Nombre d'octets ecrits correct (binaire)");
f.close();
}
}
// ── Étape 6 : Relecture binaire byte-à-byte ──────────────────
LOG_STEP(6, "Relecture binaire et verification byte-a-byte");
{
File f = LittleFS.open(TEST_FILE_BIN, "r"); // "r" = FILE_READ
check(f, "open(\"r\") - fichier binaire");
if (f) {
check((size_t)f.size() == sizeof(binData), "Taille fichier binaire correcte");
uint8_t buf[256] = {0};
size_t bytesRead = f.read(buf, sizeof(buf));
f.close();
LOG_INFO("Octets relus : %u", (unsigned)bytesRead);
bool allMatch = (bytesRead == sizeof(binData));
uint32_t errors = 0;
for (size_t i = 0; i < bytesRead && i < sizeof(binData); i++) {
if (buf[i] != binData[i]) {
allMatch = false;
errors++;
if (errors <= 5)
LOG_FAIL("Byte[%u] attendu=0x%02X obtenu=0x%02X",
(unsigned)i, binData[i], buf[i]);
}
}
if (errors > 5)
LOG_FAIL("... et %u autre(s) erreur(s).", (unsigned)(errors - 5));
check(allMatch, "Contenu binaire identique (round-trip)");
}
}
// ── Étape 7 : Listage du répertoire ──────────────────────────
LOG_STEP(7, "Listage du répertoire racine");
LOG_INFO("Contenu de '/' :");
listDir("/");
// ── Étape 8 : Test d'append ───────────────────────────────────
LOG_STEP(8, "Test d'append (ajout a un fichier existant)");
{
// Première écriture
File f1 = LittleFS.open(TEST_FILE_APPEND, "w"); // "w" = FILE_WRITE
check(f1, "open(\"w\") - fichier append (creation)");
if (f1) { f1.println("Premiere ligne."); f1.close(); }
// Ajout
File f2 = LittleFS.open(TEST_FILE_APPEND, "a"); // "a" = FILE_APPEND
check(f2, "open(\"a\") - ajout");
if (f2) { f2.println("Deuxieme ligne ajoutee."); f2.close(); }
// Relecture
File f3 = LittleFS.open(TEST_FILE_APPEND, "r"); // "r" = FILE_READ
check(f3, "open(\"r\") - verification append");
if (f3) {
String content = f3.readString();
f3.close();
bool hasBoth = content.indexOf("Premiere") >= 0 &&
content.indexOf("Deuxieme") >= 0;
check(hasBoth, "Les deux lignes presentes apres append");
LOG_INFO("Contenu apres append :\n%s", content.c_str());
}
}
// ── Étape 9 : Renommage ───────────────────────────────────────
LOG_STEP(9, "Renommage de fichier");
{
bool renamed = LittleFS.rename(TEST_FILE_APPEND, TEST_FILE_RENAMED);
check(renamed, "rename() - succes");
check(!LittleFS.exists(TEST_FILE_APPEND), "Ancien nom absent apres rename");
check(LittleFS.exists(TEST_FILE_RENAMED), "Nouveau nom present apres rename");
}
// ── Étape 10 : Suppression ────────────────────────────────────
LOG_STEP(10, "Suppression de tous les fichiers de test");
removeFile(TEST_FILE_TEXT);
removeFile(TEST_FILE_BIN);
removeFile(TEST_FILE_RENAMED);
// ── Étape 11 : Vérification de la suppression ─────────────────
LOG_STEP(11, "Verification de l'absence des fichiers supprimes");
check(!LittleFS.exists(TEST_FILE_TEXT), "TEST_FILE_TEXT absent");
check(!LittleFS.exists(TEST_FILE_BIN), "TEST_FILE_BIN absent");
check(!LittleFS.exists(TEST_FILE_RENAMED), "TEST_FILE_RENAMED absent");
LOG_INFO("Contenu final du FS (doit être vide) :");
listDir("/");
// ── Étape 12 : Démontage ──────────────────────────────────────
LOG_STEP(12, "Démontage propre de LittleFS");
LittleFS.end();
LOG_OK("LittleFS.end() appelé");
// ── Étape 13 : Résumé ─────────────────────────────────────────
Serial.println();
Serial.println(CLR_BOLD "╔════════════════════════════════════════╗" CLR_RESET);
Serial.println(CLR_BOLD "║ RÉSUMÉ DES TESTS ║" CLR_RESET);
Serial.println(CLR_BOLD "╠════════════════════════════════════════╣" CLR_RESET);
Serial.printf( CLR_BOLD "" CLR_GREEN "PASS : %-3u" CLR_BOLD " " CLR_RED "FAIL : %-3u" CLR_BOLD "\r\n" CLR_RESET,
(unsigned)g_pass, (unsigned)g_fail);
Serial.println(CLR_BOLD "╠════════════════════════════════════════╣" CLR_RESET);
if (g_fail == 0) {
Serial.println(CLR_BOLD CLR_GREEN "║ ✔ Tous les tests sont PASSÉS ! ║" CLR_RESET);
} else {
Serial.printf( CLR_BOLD CLR_RED "║ ✘ %2u test(s) en ÉCHEC ! ║\r\n" CLR_RESET,
(unsigned)g_fail);
}
Serial.println(CLR_BOLD "╚════════════════════════════════════════╝" CLR_RESET);
}
// ──────────────────────────────────────────────────────────────
// loop() rien à faire, on clignote juste la LED interne
// ──────────────────────────────────────────────────────────────
void loop()
{
// LED built-in sur la plupart des boards ESP32-S3 : GPIO 48 ou 21
// On clignote pour indiquer que le firmware tourne toujours.
#ifdef LED_BUILTIN
static bool ledState = false;
digitalWrite(LED_BUILTIN, ledState ? HIGH : LOW);
ledState = !ledState;
delay(g_fail == 0 ? 500 : 100); // lent = OK, rapide = erreur
#else
delay(1000);
#endif
}