Son principe est assez similaire au descripteur de fichier dans un système d’exploitation. Il gère tous les aspects liés spécifiquement au fichier en lui-même.
A l’initialisation, l’entrée pour le fichier concerné est recherchée :
|
[...]
// recup du premier secteur du root
if (call fat.fatReadRoot(0,buf) == FAIL)
return ret;
do {
// parcours du secteur
c = buf+offset;
if (c[0] == 0x00) { // Fin de fichier
break; // Rien a trouver
// un nom de fichier long, a skipper
} else if ((uint8_t)c[0] == 229 || c[11] == 15) {
} else if (c[11] == 0x20) { // Trouve un fichier
strncpy(fileName,c,7);
fileName[8]=’\0’;
if (!strncmp(fileName,name,strlen(name))) {
ret = SUCCESS;
break;
}
}
// passage a l’entree suivante
offset += 32;
// si depassement du secteur faut lire le suivant
if (offset >= 512) {
sector++;
offset -= 512;
call fat.fatReadRoot(sector,buf);
}
}while(c[0] != 0x00);
// renvoi des valeurs
*off = offset;
*sect = sector;
[...]
|
Une fois celui-ci trouvé, l’ensemble des variables est rempli. Dans le cas où le fichier serait vide (numéro de cluster égal à zéro), il est fait une demande de réservation. Si le fichier a été mis en veille (commande
suspend()), la recherche du cluster de fin de fichier ne sera pas réalisée car la variable contient déjà cette information.
|
/* Enregistrement du nom de fichier */
c = (buf+offset);
// Position premier cluster du contenu
dataLocation = c[26];
// Longueur du fichier
fileLength = (*(uint32_t *)&(c+sec)[28]);
// Position dans le root dir sector de l’entrée
rootSector = sec;
rootOffset = offset;
// Cluster de fin du fichier
// Si le fichier est vide
if (dataLocation < 2) {
// Réservation d’un cluster d’emblé
if (call fat.reserveCluster(&dataLocation,buf) == FAIL){
return FAIL;
}
lastCluster = dataLocation;
lastSecteur = 0;
bytesUsed = 0;
call fat.fatReadRoot(rootSector,buf);
(*(uint16_t *)&(buf+rootOffset)[26]) = dataLocation;
call fat.fatWriteRoot(rootSector,buf);
} else {
if (fileState == FILE_NOINIT) {
if ((lastCluster = call fat.fatLastCluster(dataLocation,buf))
== -1)
return FAIL;
if ((lastSecteur = call fat.fatLastSecteur(lastCluster,buf))
== -1)
return FAIL;
}
bytesUsed = fileLength & 0x1FF;
}
|
Lors d’une demande d’écriture, le tableau contenant les données est passé au système de fichiers, ainsi que le nombre d’octets déjà écrits. À l’issue de l’écriture des données, la taille du fichier est mise à jour. Ce comportement, bien que nécessitant une écriture de plus, apporte une sûreté quant aux données écrites. En effet, si une coupure d’alimentation avait lieu, dans le cas contraire, il ne serait pas possible de récupérer les données facilement.
|
|
|
8.5 Exemple d’utilisation
|
Pour montrer comment utiliser cette implémentation de la FAT16, nous allons présenter deux exemples. Le premier se contente de lancer le système de fichiers, d’ouvrir le fichier
toto.txt, dans lequel il écrit " hello World ", puis finit en fermant le fichier et le système de fichiers. Le second a pour but de montrer l’utilisation des méthodes de mise en sommeil et de réveil du système de fichiers en lisant et stockant la température, à intervalles réguliers.
|
|
|
8.5.1 Utilisation de la FAT16
|
|
configuration fatTestAppC {}
implementation {
components fatTestC as App, MainC, fatC;
components new TimerMilliC() as Timer0;
components new fileC("toto.txt");
App.Boot -> MainC.Boot;
App.Timer0 -> Timer0;
App.fatControl -> fatC;
App.file -> fileC;
App.fileControl -> fileC.fileControl;
fileC.fat -> fatC.fat;
}
|
Listing 9 : Fichier de configuration de l’application
Le premier fichier (Fig. 9) câble l’ensemble des modules, avec dans le cas du fichier la spécification du nom de celui-ci.
|
module fatTestC {
uses {
interface Boot;
interface Timer<TMilli> as Timer0;
interface SplitControl as fatControl;
interface SplitControl as fileControl;
interface fat;
interface file;
}
}
implementation {
event void Boot.booted() {
call Timer0.startOneShot(500);
}
event void Timer0.fired() {
call fatControl.start();
}
event void fatControl.startDone(error_t err){
if (err == SUCCESS) call fileControl.start();
}
event void fileControl.startDone(error_t err) {
if (err == SUCCESS)
call file.write("hello world",11)
}
event void file.writeDone(error_t err) {
if (err == SUCCESS) call fileControl.stop();
}
event void fileControl.stopDone(error_t err) {
if (err == SUCCESS) call fatControl.stop();
}
event void fatControl.stopDone(error_t err){}
[...]
}
|
Listing 10 : Fichier de l’application