Dans ce projet, nous allons réaliser l’écriture d’un fichier
sur la carte SD mais auparavant, nous allons reprendre la routine de lecture vue
précédemment pour prendre en compte la présence de plusieurs clusters.
Dans un système de fichier
FAT32, un fichier est décomposé en clusters qui sont un ensemble de
secteurs (blocs). Sur ma carte, un secteur contient 512 octets et un cluster 64
secteurs soit 32768 caractères. L’entrée du fichier dans le répertoire donne le
N° du premier cluster. Si le fichier à une taille supérieure à 32768
caractères, les clusters supplémentaires nécessaires sont indiqués dans la
table d’allocation des fichiers (FAT) se trouvant après les informations de la
partition. J’ai eu un peu de mal à trouver cette table car il faut ajouter un
nombre de secteurs réservés à l’adresse de la partition pour avoir
l’emplacement du début de la table. Sur ma carte il y a 256 secteurs réservés
mais ce chiffre est en hexadécimal et cette valeur bizarre m’a trompé plusieurs
fois. Bref sur ma carte la table d’allocation commence au 2256h secteurs. Et le
N° du cluster suivant est stocké sur 4 octets à la position indiqué par le N°
du cluster précédant : c’est clair !!!
Prenons un exemple : un fichier a besoin de 2 clusters
et le numéro du premier cluster stocké dans l’entrée est 5. Pour trouver le N°
du 2iéme cluster il faut aller le chercher dans la table à la position 4* 5
soit 20 octets sur le secteur 2256h. Et on trouvera par exemple le N° du
cluster 8 et il faudra aller chercher le suivant à la position 4 * 8 soit 32
octets sur le secteur 2256h. Et là on trouvera la valeur 0FFFFFFFh qui indique
la fin de cette chaine. Un cluster libre est renseigné à 0.
Ensuite avec chaque
N° de cluster trouvé, il faut accéder aux données du fichier en calculant
l’adresse comme suit :
Enlever 2 au N° du cluster trouvé (par exemple 5 -2 = 3), le
multiplier par le nombre de secteurs par cluster (40h) et ajouter le tout à
l’adresse du répertoire (sur ma carte c’est le secteur 4000) donc les données
de ce cluster commence au secteur 4000h + (40h *3) = 40C0h et celui du cluster
8 au secteur 4000h + (40h *6) = 4180h.
Donc la routine de lecture précédente est modifiée pour
balayer la chaine des clusters et lire les données de chaque cluster trouvé.
De plus j’en profite pour modifier la déclaration du buffer
de lecture. En effet celui-ci sera déclaré par le module appelant et son
adresse passée à la routine de lecture. Ainsi il sera possible de lire
plusieurs fichiers. Vous remarquerez que contrairement à beaucoup de langage,
nous n’avons pas de fonctions d’ouverture et de fermeture, et que nous lisons
la totalité du fichier (il aurait été possible d’envisager une lecture bloc par
bloc ou cluster par cluster).
Passons à l’écriture : Nous commençons par ajouter dans
le module carteSd1.s une routine d’écriture d’un ou plusieurs blocs. Elle est
pratiquement identique à la routine de lecture sauf le test du code de
disponibilité de la carte et l’envoi des données du buffer vers la carte.
Dans le module repertoire.s, nous ajoutons les routines
nécessaires à l’écriture. C’est compliqué car il y a plusieurs cas à
gérer : le fichier existe déjà et dans ce cas si la nouvelle taille est
supérieur à l’ancienne, il faut vérifier que cette taille ne nécessite pas un
ou plusieurs clusters supplémentaires. Si c’est le cas, il faut parcourir la
chaine des adresses des clusters pour trouver le dernier puis trouver des
clusters vides et les ajouter à la chaine.
Attention : je n’ai pas programmé le cas où la taille
est plus petite et qu’il faut libérer des clusters qui ne sont plus utilisés.
Ensuite, dans tous les cas, il faut écrire les données du
buffer d’écriture dans les clusters et mettre à jour l’entrée du fichier dans
le répertoire avec la nouvelle taille.
Si le fichier n’existe pas sur la carte, il faut tout créer :
chercher un cluster vide dans la table d’allocation, allouer autant de clusters
que nécessaire, écrire les données du buffer dans les clusters puis créer une
entrée complète dans le répertoire principal.
Attention, je n’ai pas programmé l’écriture dans un sous
répertoire !!! ni le retour arrière sur des données déjà écrites en cas d’erreur
d’écriture d’une entité.
La création de l’entrée pose un petit problème : en
effet il faut renseigner la date et l’heure de création et le timbre
(timestamp) or le Raspberry ne comporte pas d’horloge interne alimentée par une
pile pour conserver une date et une heure et nous n’avons pas d’accès à internet
dans ce contexte baremetal pour y récupérer la date et heure Internet. Donc j’ai
pris pour option de prendre la date et l’heure de l’entrée précédente !!!!!.
Si vous continuez à développer dans ce contexte et si vous voulez avoir une
date et une heure correcte, il vous faudra ajouter au Raspberry une carte
horloge externe alimentée en permanence.
Je dois vous avouer que ces routines m’ont donné du mal à
écrire et à mettre au point. Elles ne sont donc pas bien écrites et il faudrait
les améliorer. L’utilisation de nombreux registres compliquent la compréhension
de la programmation : il y a donc du travail à faire !!!
Pour tester tout cela, j’ai modifié le module kernel.s pour
avoir des commandes plus évoluées comme :
Lire nomdefichier ou
Ecrire nomdefichier1
nomdefichier2 (en fait c’est copier le
fichier 1 dans le fichier 2)
Ou ecrire nomdefichier1 nomdefichier2 taille
pour tester les changements de taille.
J’ai aussi modifié la routine uart_send (dans le module
mini_uart.s) pour vérifier les caractères envoyés car j’ai de temps en temps un
redémarrage de window10 avec une erreur du driver prolific !!. Car je
pensais que le problème venait de l’envoi de caractères non imprimables. Hélas
cette correction n’est pas efficace !!!
Voilà voilà le projet complet.
Aucun commentaire:
Enregistrer un commentaire