Bonjour,
J'avance...
Maintenant que j'arrive à lire ma carte SD, je veux naviguer dedans avec la librairie FatFs.
Encore une fois, ce message serait peut-être plus à sa place dans la section Programmation, n'hésitez pas à déplacer si besoin.
Mon but serait d'avoir 4 boutons : fichier/dossier suivant, fichier/dossier précédent, ouvrir et fermer. Rien d'exceptionnel quoi, je ne pense pas être le premier à vouloir faire ça.
Sauf que malgré des heures de recherche, je ne trouve pas de moyen "simple" d'implémenter la fonction "Précédent". Les éléments d'un dossiers sont lus dans l'ordre séquentiel et on ne peut pas revenir en arrière.
Je suis très surpris de ne trouver aucune doc ou aucun tuto sur ce sujet dans les méandres du web...
J'ai imaginé 2 solutions, qui fonctionnent très bien mais qui ne me semblent pas très "propres".
J'aimerais avoir votre avis éclairé sur la meilleure méthode, voire sur LA méthode qu'on utilise en général et à laquelle je n'ai pas pensé.
Premère solution
- A l'ouverture d'un dossier, je scanne l'ensemble du dossier pour compter le nombre d'éléments NbFichiers (fichiers et dossiers) présents.
- Je reviens au début avec f_rewinddir() et place mon compteur d'index NumFichier à 0.
- Lors d'un appui sur "Précédent" :
- je crée une variable FichierCible égale à NumFichier-1 ou NbFichiers si mon index était sur le premier fichier du dossier afin de reboucler sur la dernière entrée.
- Je reviens au début du dossier avec f_rewinddir()
- Je relis le dossier en séquence avec f_readdir() jusqu'à arriver à mon index FichierCible.
Ca me parait un peu absurde. Si un dossier contient de nombreux fichiers et que l'on se trouve vers la fin de celui-ci, on va devoir rebalayer l'ensemble. Ca fait beaucoup de ressources processeur utilisées pour pas grand chose...
Deuxième solution
En fouinant dans le fichier ff.c du module FatFs, j'ai trouvé la fonction dir_sdi() qui sert dans f_rewinddir() et se dirige directement à l'index indiqué.
- Donc à l'ouverture d'un dossier, je scanne toutes ses entrées, cette fois pour enregistrer les index de chaque élément dans un tableau.
- Je reviens au début avec f_rewinddir() et place mon compteur d'index NumFichier à 0.
- Lors d'un appui sur "Précédent", j'utilise simplement ma fonction f_readthisdir() ci-dessous
Cette fois, l'accès à un fichier est écourté, je ne re-scanne plus tout le dossier pour trouver mon fichier.
En revanche, je suis obligé d'utiliser un tableau d'index qui prendra plus de place en mémoire.
J'ai cru comprendre qu'il était impossible de créer des tableaux dynamiquement alloués avec les µC, du coup, je suis également obligé de limiter le nombre de fichiers par dossier (ce qui n'est pas si problématique, ce ne serait de toutes façons pas très pratique de placer un grand nombre de fichiers dans un dossier).
Mon code final utilise, dans la deuxième solution, beaucoup plus de ressources Data (+1000 bytes), et à quelque chose près autant de ressources Program (+300 bytes) du Pic.
Par contre, j'imagine que le temps de traitement d'un appui sur le bouton "Précédent" sera beaucoup plus court, surtout si le dossier est gros.
Voilà. Si vous avez un avis sur ce qu'il faut ou ne faut pas faire, je suis tout ouïe. Particulièrement si vous connaissez une méthode plus simple et/ou plus économe en ressources, évitant par exemple de scanner l'ensemble du dossier à son ouverture.
Merci beaucoup.
Ci-dessous, quelques bouts de code pour illustrer le problème :
Code:// FONCTION f_readdir() ORIGINALE (ff.c) /*-----------------------------------------------------------------------*/ /* Read Directory Entries in Sequence */ /*-----------------------------------------------------------------------*/ FRESULT f_readdir ( DIR* dp, /* Pointer to the open directory object */ FILINFO* fno /* Pointer to file information to return */ ) { FRESULT res; DEFINE_NAMEBUF; res = validate(dp); /* Check validity of the object */ if (res == FR_OK) { if (!fno) { res = dir_sdi(dp, 0); /* Rewind the directory object */ } else { INIT_BUF(*dp); res = dir_read(dp, 0); /* Read an item */ if (res == FR_NO_FILE) { /* Reached end of directory */ dp->sect = 0; res = FR_OK; } if (res == FR_OK) { /* A valid entry is found */ get_fileinfo(dp, fno); /* Get the object information */ res = dir_next(dp, 0); /* Increment index for next */ if (res == FR_NO_FILE) { dp->sect = 0; res = FR_OK; } } FREE_BUF(); } } LEAVE_FF(dp->fs, res); } // FONCTION f_readthisdir() RAJOUTÉE POUR LA SECONDE SOLUTION (ff.c) #if _USE_SEEK /*-----------------------------------------------------------------------*/ /* Read Directory Entries by Index */ /*-----------------------------------------------------------------------*/ FRESULT f_readthisdir ( DIR* dp, /* Pointer to the open directory object */ FILINFO* fno, /* Pointer to file information to return */ UINT index /* Index of directory element to read */ ) { FRESULT res; DEFINE_NAMEBUF; res = validate(dp); /* Check validity of the object */ if (res == FR_OK) { res = dir_sdi(dp, index); /* Seek to the directory object */ if (res == FR_OK) { INIT_BUF(*dp); res = dir_read(dp, 0); /* Read an item */ if (res == FR_NO_FILE) { /* Reached end of directory */ dp->sect = 0; res = FR_OK; } } if (res == FR_OK) { /* A valid entry is found */ get_fileinfo(dp, fno); /* Get the object information */ res = dir_next(dp, 0); /* Increment index for next */ if (res == FR_NO_FILE) { dp->sect = 0; res = FR_OK; } FREE_BUF(); } } LEAVE_FF(dp->fs, res); } #endif // FONCTION DE SCANNAGE DES INDEX POUR LA SECONDE SOLUTION (Main.c) /*--------------------------------------------------------------------------------------*/ /* Scanne un dossier et enregistre l'index de chaque élément */ /*--------------------------------------------------------------------------------------*/ FATFS FatFs; // FatFs work area needed for each volume DIR Dossier; // Dossier actuellement parcouru FILINFO Fichier; // Informations du fichier pointé UINT Index[255], NumFichier, NbFichiers; static FRESULT ScanDir(void){ FRESULT res; UINT currentIndex; Index[0] = NumFichier = 0; do { NumFichier++; do { currentIndex = Dossier.index; // Dossier.index indique en fait l'index du fichier suivant à cause de l'appel à dir_next() // Donc on enregistre l'index avant de scanner l'élément suivant res = f_readdir(&Dossier, &Fichier); if (res != FR_OK) return res; } while (Fichier.fname[0] == '.'); // On saute les fichiers cachés (on le fera également lors de la lecture f_readdir()) if (Fichier.fname[0] != 0) Index[NumFichier] = currentIndex; else Index[NumFichier] = 0; } while (Fichier.fname[0] != 0); NbFichiers = NumFichier - 1; res = f_rewinddir(&Dossier); NumFichier = 0; return res; // FONCTION PRECEDENT (Main.c) /*--------------------------------------------------------------------------------------*/ /* Cheche le fichier précédent */ /*--------------------------------------------------------------------------------------*/ FRESULT ReadPrev(void) { FRESULT res; if (NumFichier < 2) NumFichier = NbFichiers; else NumFichier--; res = f_readthisdir (&Dossier, &Fichier, Index[NumFichier]); if (Fichier.fname[0] == 0) return FR_NO_FILE; return res; } }
-----