sizeof(tblNomFic) te donne la taille de la variable tblNomFic et donc de tous les éléments qu'elle contient.
A priori tu peux connaître le nombre de fichiers dans ta boucle while. Pourquoi ne pas le faire ici ?
sizeof(tblNomFic) te donne la taille de la variable tblNomFic et donc de tous les éléments qu'elle contient.
A priori tu peux connaître le nombre de fichiers dans ta boucle while. Pourquoi ne pas le faire ici ?
Oui effectivement, c'est ce que je fais à présent avec:
File myFile; //Fichier
String tblNomFic[10]; //Le nom des fichiers
int nbFichier; //Nombre de fichier
/* SETUP */
void setup() {
//Initialiser la carte SD
if(initSD()) {
//Lister les fichiers de configuration présent
nbFichier = listeFichier("test");
}
//Fermer le fichier
myFile.close();
Serial.println(tblNomFic[0]);
Serial.println(tblNomFic[1]);
Serial.println(tblNomFic[2]);
Serial.println(tblNomFic[3]);
Serial.println("");
Serial.println(nbFichier);
}
/* LOOP */
void loop() {
}
/* FONCTION listerFichier() */
int listeFichier(String path) {
int count = 0;
myFile = SD.open(path); //Ouvre la racine
//Tant que c'est vrai
while(true) {
//Prend le nom du fichier
File entry = myFile.openNextFile();
//Si c'est la fin
if(!entry) {
break; //Sortir de la boucle
}
//Rentre le nom de fichier dans un tableau
tblNomFic[count] = entry.name();
count++; //Compter le nombre de fichier
}
//Retourner le nombre de fichier
return count;
}
J'ai un petit souci pour transmettre mon chemin. J'en profite de la fonction pour prévoir pour le cas ou on choisirais volontairement un chemin différent. On ne sait jamais dans une autre application ça peut-être utile.
Là, si j'ai bien compris, ce qui ne va pas c'est l'arrivé en string pour aller sur un char*. Je cherche une solution à ce niveau.
Bonjour,
En effet, ça fonctionne ça:
/* FONCTION listerFichier() */
int listeFichier(String chemin) {
int count = 0;
char path[32];
//Conversion du chemin
chemin.toCharArray(path, 32);
//Ouvre ce qui est défini par le chemin
myFile = SD.open(path);
//Tant que c'est vrai
while(true) {
//Prend le nom du fichier
File entry = myFile.openNextFile();
//Si c'est la fin
if(!entry) {
break; //Sortir de la boucle
}
//Rentre le nom de fichier dans un tableau
tblNomFic[count] = entry.name();
count++; //Compter le nombre de fichier
}
//Retourner le nombre de fichier
return count;
}
Maintenant je pense qu'il me faut créer un répertoire pour chaque choses. Ainsi, je chargerais divers tableau en fonction de.
Deux solutions s'opposes. L'une permet de sélectionner le type de tableau avec un case. Mais j'aime pas cette méthode. L'autre est de charger dans un tableau les fichier du répertoire 1 puis de copier le contenu du tableau dans un tableau de modèle. De passé au tableau de fichier de mémo, puis de faire la même dans un second tableau. Ainsi, je pense éviter de devoir à chaque fois re écrire un code spécifique pour chaque répertoire. Enfin, c'est ce que je pense.
Ou alors, je passe en paramètre le nom du tableau que l'on veut chargé. C'est peut-être plus simple non ?
Autre chose. Maintenant que j'ai mes fichiers de dispo, comment je vais faire pour créer un tableau de type clef=valeur ? Sachant que dans mon fichier c'est clef=valeur ?
Merci pour votre aide.
Bon j'ai fait une modif avec des if. Ça me correspond pas trop mal et surtout ça fonctionne !
/* FONCTION listerFichier() */
int listeFichier(String chemin) {
int count = 0;
char path[32];
//Conversion du chemin
chemin.toCharArray(path, 32);
//Ouvre ce qui est défini par le chemin
myFile = SD.open(path);
//Tant que c'est vrai
while(true) {
//Prend le nom du fichier
File entry = myFile.openNextFile();
//Si c'est la fin
if(!entry) {
break; //Sortir de la boucle
}
//Si c'est le répertoire /modeles/
if(chemin == "/modeles/") {
//Rentre le nom de fichier dans le tableau des noms de modèles
tblFicMdle[count] = entry.name();
}
//Si c'est le répertoire /sauvegarde/
if(chemin == "/svgde/") {
//Rentre le nom de fichier dans le tableau des noms de sauvegarde
tblFicSvg[count] = entry.name();
}
count++; //Compter le nombre de fichier
}
//Retourner le nombre de fichier
return count;
}
Reste maintenant à charger les valeurs contenu dans les fichier.
Je commence avec la sauvegarde qui ira chercher les données d'un autre fichier sous /svgde/memo.txt.
Ce fichier memo.txt contient:
Modele = modele001
Vaut-il mieux faire un tableau à deux dimensions. Ainsi si j'appelle ma sauvegarde avec l'index Model, je saurais qu'il faut que j'aille chercher modele001.txt. ?
Sachant que d'autres valeurs viendrons par la suite.
Et bien, c'est tiré par les cheveux mais je suis arrivé à quelque-chose.
Donc au démarrage, on charge deux répertoire dans un tableau chacun.
Dans un des répertoire on a un fichier qui dit quel fichier était ouvert et qui doit directement donné les valeurs à chargé.
Bon, j'en suis à cette étape ou je charge bien le fichier de configuration, mais je dois maintenant choisir entre deux cas dans mon fichier:
Modele = modele001
OU
modele001 //le model
Dans un cas il faudra éliminer le commentaire mais c'est plus simple à gérer. ou bien, moi qui suis un vrai geek et surtout un poil dans la main, on demande la clef dans un tableau à deux dimensions et on a la valeur.
Je suis tenter par le cas 2 avec Modele = modele001.
A ce moment là, comment je puis modifier ma fonction en bas pour charger les données spécifique. Sachant que la même fonction va me servir pour charger et le fichier de conf type sauvegarde, et le fichier du modèle. Donc deux tableaux à rappelés.
Le code actuel:
#define SIZE_BUFFER 32 //Nombre de case du buffer
File myFile; //Fichier
String tblFicMdle[10]; //Le tableau des noms des fichiers modèles
String tblFicSvg[10]; //Le tableau des noms des fichiers de sauvegardes
int nbFichierMdle; //Nombre de fichier
//Initialiser la carte SD
if(initSD()) {
//Lister les fichier de sauvegardes
listeFichier("/svgde/");
//Lister les fichiers de configuration modèle
nbFichierMdle = listeFichier("/modeles/");
//Ouvrir le fichier de sauvegarde memo.txt
ouvrirFichier("/svgde/" + tblFicSvg[0]);
}
else {
//Charger les valeurs par défaut de la radio
}
//Fermer le fichier
//myFile.close();
/*
Serial.println("Modeles :");
Serial.println(tblFicMdle[0]);
Serial.println(tblFicMdle[1]);
Serial.println(tblFicMdle[2]);
Serial.println("");
Serial.println(nbFichierMdle);
Serial.println("");
Serial.println("Sauvegarde :");
Serial.println(tblFicSvg[0]);
*/
/* FONCTION initSD() */
boolean initSD() {
clearLcd(); //Effacer l'écran
ecrireLcd("Init SD Card...", 01); //Ecrire
//Si la carte n'est pas présente ou qu'elle est en défaut
if(!SD.begin(4)) {
//Afficher l'écran LCD
clearLcd(); //Effacer l'écran
ecrireLcd("Init SD Card failed", 01); //Ecrire
delay(1000);
return false;
}
clearLcd(); //Effacer l'écran
ecrireLcd("Init SD Card done", 01); //Ecrire
delay(1000);
return true;
}
/* FONCTION listerFichier() */
int listeFichier(String chemin) {
int count = 0;
char path[SIZE_BUFFER];
//Conversion du chemin
chemin.toCharArray(path, SIZE_BUFFER);
//Ouvre ce qui est défini par le chemin
myFile = SD.open(path);
//Tant que c'est vrai
while(true) {
//Prend le nom du fichier
File entry = myFile.openNextFile();
//Si c'est la fin
if(!entry) {
break; //Sortir de la boucle
}
//Si c'est le répertoire /modeles/
if(chemin == "/modeles/") {
//Rentre le nom de fichier dans le tableau des noms de modèles
tblFicMdle[count] = entry.name();
}
//Si c'est le répertoire /sauvegarde/
if(chemin == "/svgde/") {
//Rentre le nom de fichier dans le tableau des noms de sauvegarde
tblFicSvg[count] = entry.name();
}
count++; //Compter le nombre de fichier
}
//Fermer le fichier
myFile.close();
//Retourner le nombre de fichier
return count;
}
/* FONCTION qui ouvre un fichier */
void ouvrirFichier(String chemin) {
//Variables
char path[SIZE_BUFFER];
//Transforme le chemin en tableau de carractères
chemin.toCharArray(path, SIZE_BUFFER);
//Ouvre le fichier de configuration
myFile = SD.open(path, FILE_READ);
//Erreur d'ouverture du fichier
if(!myFile) {
clearLcd(); //Effacer l'écran
ecrireLcd("Fichier failed", 01); //Ecrire
for(;;); //Boucle infini (peut tre remplacer par un bouton valider)
}
//Tant que ce n'est pas la fin du fichier
while(myFile.available()) {
Serial.write(myFile.read());
}
//Fermer le fichier
myFile.close();
delay(1000);
}
Pour le moment je me contente d'afficher le résultat:
Modele = modele001
Dernier point, j'aimerais tant que faire ce peu que ça soit pas trop compliqué à digéré de façon à m'y retrouver ensuite. :ccool:
Merci encore et me blâmer pas trop. J'essaie d'apprendre par al pratique.
Bonjour,
J'avance un peu mais je me heurte à une boucle infini. En partant du sujet skyduino j'ai fait mon code comme suit:
#define SIZE_BUFFER 32 //Nombre de case du buffer
char bufferConf[SIZE_BUFFER]; //Le buffer des fichiers de conf
String tblConfSvg[clef][valeur]; //Tableau de configuration Sauvegarde
String tblConfMdle[clef][valeur]; //Tableau de configuration valeur
/* SETUP */
void setup() {
//Initialiser la carte SD
if(initSD()) {
//Lister les fichier de sauvegardes
listeFichier("/svgde/");
//Lister les fichiers de configuration modèle
nbFichierMdle = listeFichier("/modeles/");
//Ouvrir le fichier de sauvegarde memo.txt
ouvrirFichier("/svgde/", tblFicSvg[0]);
}
else {
//Charger les valeurs par défaut de la radio
}
}
/* LOOP */
void loop() {
}
/* FONCTION initSD() */
boolean initSD() {
clearLcd(); //Effacer l'écran
ecrireLcd("Init SD Card...", 01); //Ecrire
//Si la carte n'est pas présente ou qu'elle est en défaut
if(!SD.begin(4)) {
//Afficher l'écran LCD
clearLcd(); //Effacer l'écran
ecrireLcd("Init SD Card failed", 01); //Ecrire
delay(1000);
return false;
}
clearLcd(); //Effacer l'écran
ecrireLcd("Init SD Card done", 01); //Ecrire
delay(1000);
return true;
}
/* FONCTION listerFichier() */
int listeFichier(String chemin) {
int count = 0;
char path[SIZE_BUFFER];
//Conversion du chemin
chemin.toCharArray(path, SIZE_BUFFER);
//Ouvre ce qui est défini par le chemin
myFile = SD.open(path);
//Tant que c'est vrai
while(true) {
//Prend le nom du fichier
File entry = myFile.openNextFile();
//Si c'est la fin
if(!entry) {
break; //Sortir de la boucle
}
//Si le nombre de fichier est plus important que le nombre de place en tableau
if(count == nbFic) {
break; //Sortir de la boucle
}
//Si c'est le répertoire /modeles/
if(chemin == "/modeles/") {
//Rentre le nom de fichier dans le tableau des noms de modèles
tblFicMdle[count] = entry.name();
}
//Si c'est le répertoire /sauvegarde/
if(chemin == "/svgde/") {
//Rentre le nom de fichier dans le tableau des noms de sauvegarde
tblFicSvg[count] = entry.name();
}
count++; //Compter le nombre de fichier
}
//Fermer le fichier
myFile.close();
//Retourner le nombre de fichier
return count;
}
/* FONCTION qui ouvre un fichier */
void ouvrirFichier(String chemin, String fic) {
/*
String tblConfSvg[clef][valeur]; //Tableau de configuration Sauvegarde
String tblConfMdle[clef][valeur]; //Tableau de configuration valeur
*/
//Variables
char path[SIZE_BUFFER], *key, *val;
int i, bufferLenght;
//Re crée le chemin
chemin = chemin + fic;
//Transforme le chemin en tableau de carractères
chemin.toCharArray(path, SIZE_BUFFER);
//Ouvre le fichier de configuration
myFile = SD.open(path, FILE_READ);
//Erreur d'ouverture du fichier
if(!myFile) {
clearLcd(); //Effacer l'écran
ecrireLcd("Fichier failed", 01); //Ecrire
for(;;); //Boucle infini (peut tre remplacer par un bouton valider)
}
//Tant que ce n'est pas la fin du fichier
while(myFile.available()) {
//Récupère la ligne
i=0;
while((bufferConf[i++] = myFile.read()) != '\n') {
//Si la ligne dépasse le buffer
if(i == SIZE_BUFFER) {
//Finir la ligne et stopper la lecture
while(myFile.read() != '\n') {
break;
}
}
}
bufferLenght = i; //Garder en mémoire le nombre de char
bufferConf[--i] = '\0'; //Finalise la chaine en virant le \n
//Ignore les lignes vides, les commentaires # et //
if(bufferConf[0] == '\0' || bufferConf[0] == '#' || bufferConf[0] == '//') {
continue;
}
//Cherche l'emplacement de la clef en ignorant les espaces et tabulations
i = 0;
while(bufferConf[i] = ' ' || bufferConf[i] == '\t') {
//Ignore les lignes contenant uniquement des espaces ou des tabulations
if(++i == bufferLenght) {
break;
}
key = &bufferConf[i];
/*
Ici boucle inini ?
*/
//Cherche l'emplacement du séparateur
while(bufferConf[i] != '=') {
//Ignore les espaces et tabulations
if(bufferConf[i] == ' ' || bufferConf[i] == '\t') {
bufferConf[i] = '\0';
}
//Ignore les lignes mal formés
if(++i == bufferLenght) {
break;
}
}
/*
//Gère les lignes mal formés
if(i == bufferLenght) {
continue;
}
bufferConf[i++] = '\0'; //Transforme me séparateur = en \o et continue
//Cherche l'emplacement de la valeur en ignorant espaces et tabulations
while(bufferConf[i] == ' ' || bufferConf[i] == '\t') {
//Ignore les lignes contenant uniquement des espaces ou des tabulations
if(++i == bufferLenght) {
break;
}
//Gère les lignes mal formés
if(i == bufferLenght) {
continue;
}
val = &bufferConf[i];
//Charger la clef et la valeur dans le tableau à deux dimension
Serial.println(key);
Serial.println(val);
}
*/
Serial.println(key);
}
/*
//Si c'est le répertoire /sauvegarde/
if(chemin == "/svgde/") {
}
//Si c'est le répertoire /modeles/
if(chemin == "/modeles/") {
}
*/
//Serial.write(myFile.read());
}
Serial.println("Fin fichier");
//Fermer le fichier
myFile.close();
delay(1000);
}
A un endroit, je pose la question de la boucle infini. Un test m'a prouvé que l'on ne s'arrêtais pas sur le '=' et que 1 s'incrémentais sauvagement ! Si je vire le while en le mettant en commentaire, je vais bien jusqu'à la fin de fichier. Donc la condition n'arrive jamais. Je cherche pourquoi.
Pour rappel, mon fichier ne contient qu'une ligne étnant : Modele = modele001.
Merci.
J'y suis arrivé, j'ai bien ma key et ma val. Quelques erreur dans l'indentation et saisie de code. Bref c'est corrigé.
Par contre, maintenant j'aimerais savoir comment liée une clef à sa valeur dans un tableau. Ainsi si j'appelle la clef, j'obtiendrais sa valeur.
Merci pour votre aide la dessus.
Contrairement a d'autres langages comme PHP ou JavaScript, il n'est pas possible en C d'indéxer un tableau par une clé.
Il va falloir le faire "à la main"
Le plus simple est d'utiliser un tableau de structure :
#define NBKEY 20
#define KEYLEN 20
struct {
char key[KEYLEN];
int val; // ou autre type
} TabKeyVal[NBKEY];
Ce qui te donne un tableau a 20 élements dans lequel tu peux mémoriser tes couples.
Par contre il faudra forcément chercher chaque fois que tu veux une valeur.
Par exemple
int getVal( const char *key, int *pVal )
{
int i;
for ( i = 0 ; i < NBKEY ; i++ )
if ( 0 == strcmp( key, TabKeyVal[i].key ) )
{
*pVal = TabKeyVal[i].val;
return 1;
}
return 0;
}
En C++ avancé il existe des moyens de faire des collections mais cela n'est pas disponible a ma connaissance sur ATmega.
Au mieux, tu peux encapsuler la structure et ses méthodes d'accès dans une classe.
Ok pour cette méthode.
Je viens de trouvé par hasard ceci : Arduino Playground - HashMap Library
Ça correspond à ce que je voulais faire mais hélas j'ai pas l'impression que ça fonctionne.
#include <HashMap.h>
#define SIZE_BUFFER 32 //Nombre de case du buffer
const int nbFic = 10; //Nombre de fichier potentiel à scruter
const byte SIZE_HASH = 2; //Nombre de hshtable
char bufferConf[SIZE_BUFFER]; //Le buffer des fichiers de conf
HashType<char*, String> hashRawArray[SIZE_HASH];
HashMap<char*, String> hashMapConfSvg = HashMap<char*, String>(hashRawArray, SIZE_HASH);
File myFile; //Fichier
String tblFicMdle[nbFic]; //Le tableau des noms des fichiers modèles
String tblFicSvg[nbFic]; //Le tableau des noms des fichiers de sauvegardes
int nbFichierMdle; //Nombre de fichier
/* SETUP */
void setup() {
//Initialiser la carte SD
if(initSD()) {
//Lister les fichier de sauvegardes
listeFichier("/svgde/");
//Lister les fichiers de configuration modèle
nbFichierMdle = listeFichier("/modeles/");
//Ouvrir le fichier de sauvegarde
ouvrirFichier("/svgde/", tblFicSvg[0]);
}
else {
//Charger les valeurs par défaut de la radio
}
}
/* LOOP */
void loop() {
}
/* FONCTION initLCD */
void initLcd() {
//Initialisation de l'écran par I2C
Wire.begin(); //Amorce la connection sur SDA et SCL
Wire.beginTransmission(adresseLcd); //Appelle l'écran LCD
Wire.write((byte)0x00); //Assigne un null
Wire.write((byte)0x0C); //Effacer l'écran
Wire.write((byte)0x13); //Allume le rétro-éclairage
Wire.write((byte)0x04); //Ne pas afficher le curseur
Wire.endTransmission(); //Ferme la connexion sur SDA et SCL
}
/* FONCTION ecrireLcd */
void ecrireLcd(String texte, int positionEcran) {
//Initialisation de l'écran par I2C
Wire.begin(); //Amorce la connection sur SDA et SCL
Wire.beginTransmission(adresseLcd); //Appelle l'écran LCD
Wire.write((byte)0x00); //Assigne un null
Wire.write((byte)0x02); //Placer le curseur
Wire.write(positionEcran); //Sur l'écran
Wire.print(texte); //Ecrire un texte
Wire.endTransmission(); //Ferme la connexion sur SDA et SCL
}
/* FONCTION ecrireLcdChar */
void ecrireLcdChar(char texte[32], int positionEcran) {
//Initialisation de l'écran par I2C
Wire.begin(); //Amorce la connection sur SDA et SCL
Wire.beginTransmission(adresseLcd); //Appelle l'écran LCD
Wire.write((byte)0x00); //Assigne un null
Wire.write((byte)0x02); //Placer le curseur
Wire.write(positionEcran); //Sur l'écran
Wire.write(texte); //Ecrire un texte
Wire.endTransmission(); //Ferme la connexion sur SDA et SCL
}
/* FONCTION clearLcd() */
void clearLcd() {
//Initialisation de l'écran par I2C
Wire.begin(); //Amorce la connection sur SDA et SCL
Wire.beginTransmission(adresseLcd); //Appelle l'écran LCD
Wire.write((byte)0x00); //Assigne un null
Wire.write((byte)0x0C); //Effacer l'écran
Wire.endTransmission(); //Ferme la connexion sur SDA et SCL
}
/* FONCTION initSD() */
boolean initSD() {
clearLcd(); //Effacer l'écran
ecrireLcd("Init SD Card", 01); //Ecrire
//Si la carte n'est pas présente ou qu'elle est en défaut
if(!SD.begin(4)) {
ecrireLcd("Non presente", 21); //Ecrire
return false;
}
ecrireLcd("Sd card... Ok", 21); //Ecrire
delay(1000);
return true;
}
/* FONCTION listerFichier() */
int listeFichier(String chemin) {
int count = 0;
char path[SIZE_BUFFER];
//Conversion du chemin
chemin.toCharArray(path, SIZE_BUFFER);
//Ouvre ce qui est défini par le chemin
myFile = SD.open(path);
//Tant que c'est vrai
while(true) {
//Prend le nom du fichier
File entry = myFile.openNextFile();
//Si c'est la fin
if(!entry) {
break; //Sortir de la boucle
}
//Si le nombre de fichier est plus important que le nombre de place en tableau
if(count == nbFic) {
break; //Sortir de la boucle
}
//Si c'est le répertoire /modeles/
if(chemin == "/modeles/") {
//Rentre le nom de fichier dans le tableau des noms de modèles
tblFicMdle[count] = entry.name();
}
//Si c'est le répertoire /sauvegarde/
if(chemin == "/svgde/") {
//Rentre le nom de fichier dans le tableau des noms de sauvegarde
tblFicSvg[count] = entry.name();
}
count++; //Compter le nombre de fichier
}
//Fermer le fichier
myFile.close();
//Retourner le nombre de fichier
return count;
}
/* FONCTION qui ouvre un fichier */
void ouvrirFichier(String chemin, String fic) {
//Variables
char path[SIZE_BUFFER], *key, *val;
int i, bufferLenght, lineCounter = 0;
clearLcd(); //Effacer l'écran
ecrireLcd("Fichier en lecture", 01); //Ecrire
//Re crée le chemin
chemin = chemin + fic;
//Transforme le chemin en tableau de carractères
chemin.toCharArray(path, SIZE_BUFFER);
//Ouvre le fichier de configuration
myFile = SD.open(path, FILE_READ);
//Erreur d'ouverture du fichier
if(!myFile) {
clearLcd(); //Effacer l'écran
ecrireLcd("Pb fichier", 01); //Ecrire
for(;;); //Boucle infini (peut tre remplacer par un bouton valider)
}
//Tant que ce n'est pas la fin du fichier
while(myFile.available()) {
//Récupère la ligne
i=0;
while((bufferConf[i++] = myFile.read()) != '\n') {
//Si la ligne dépasse le buffer
if(i == SIZE_BUFFER) {
//Finir la ligne et stopper la lecture
while(myFile.read() != '\n') {
break;
}
}
}
bufferLenght = i; //Garder en mémoire le nombre de char
bufferConf[--i] = '\0'; //Finalise la chaine en virant le \n
++lineCounter; //Incrémenter le nombre de ligne
//Ignore les lignes vides, les commentaires # et //
if(bufferConf[0] == '\0' || bufferConf[0] == '#' || bufferConf[0] == '//') {
continue;
}
//Cherche l'emplacement de la clef en ignorant les espaces et tabulations
i = 0;
while(bufferConf[i] == ' ' || bufferConf[i] == '\t') {
//Ignore les lignes contenant uniquement des espaces ou des tabulations
if(++i == bufferLenght) {
break;
}
}
//Gère les lignes mal formés
if(i == bufferLenght) {
continue;
}
key = &bufferConf[i];
//Cherche l'emplacement du séparateur
while(bufferConf[i] != '=') {
//Ignore les espaces et tabulations
if(bufferConf[i] == ' ' || bufferConf[i] == '\t') {
bufferConf[i] = '\0';
}
//Ignore les lignes mal formés
if(++i == bufferLenght) {
break;
}
}
//Gère les lignes mal formés
if(i == bufferLenght) {
continue;
}
bufferConf[i++] = '\0'; //Transforme me séparateur = en \o et continue
//Cherche l'emplacement de la valeur en ignorant espaces et tabulations
while(bufferConf[i] == ' ' || bufferConf[i] == '\t') {
//Ignore les lignes contenant uniquement des espaces ou des tabulations
if(++i == bufferLenght) {
break;
}
}
//Gère les lignes mal formés
if(i == bufferLenght) {
continue;
}
val = &bufferConf[i];
/*
String tblConfSvg[clef][valeur]; //Tableau de configuration Sauvegarde
String tblConfMdle[clef][valeur]; //Tableau de configuration valeur
*/
//Si c'est le répertoire /sauvegarde/
if(chemin == "/svgde/") {
hashMapConfSvg[lineCounter](key, val);
}
//Si c'est le répertoire /modeles/
if(chemin == "/modeles/") {
}
Serial.println(lineCounter);
Serial.println(key);
Serial.println(val);
}
Serial.println(hashMapConfSvg.getIndexOf("Modele"), DEC);
Serial.println(hashMapConfSvg.getValueOf("Modele"));
//Fermer le fichier
myFile.close();
ecrireLcd("Fichier Ok", 21); //Ecrire
delay(1000);
}
Ceci alourdis pas mal le code le coup du hashtable. Mais tu a peut-être raison, ça m'a l'air aussi simple avec la recherche dans le tableau. Laquelle des deux solutions est la plus pratique / meilleure et surtout non consommatrice de ressources ?
Edit, je laisse tomber les hashtable. Beaucoup de souci d'upload à cause de cette librairie !
Retour à ta solution
Et si je chargais dans un premier tableau la clef, et dans un autre la valeur.
J'appelle la clef, qui me retourne sa position, avec la position je retrouve la valeur
Le tour serais joués sans se prendre la tête avec un tableau de structure XD
Un tableau de structure est juste plus propre du point de vue codage.
Sinon, avec 2 tableaux ca revient au même.
La, pour le moment mes tableaux sont vide malgres le fait que j'ai bien key et val qui ont des données.
Ok pour le fait que ça soit plus propre. À ce moment la, j'ai peut être intérêt à basculer une partie de mes fonctions en classe.
Des mon retour, je regarde pourquoi mes tableaux de String restent vide et je passe aux classes.
De retour à la maison, je me rend compte que key et val sont des char*.
Donc il me faut les convertir vers char ou String. Je cherche comment !
Tout simplement avec le constructeur de la classe String :
char* charArray = "Hello world!";
String str = String(charArray);
++
String str = String(charArray);
Voici un très bon exemple de mauvaise utilisation de String
A droite du signe = tu appelles le constructeur de la classe String. Ce qui crée un objet String temporaire, alloue de la mémoire pour stocker la chaine de caractère, copie la chaine de caractère dans l'espace mémoire ainsi alloué.
A gauche du signe égal tu a la définition d'une variable str de type String. Ce qui crée l'objet String appelé str.
Le signe égal signifie qu'il y a copié du membre de droite vers le membre de gauche.
L'objet temporaire est copié dans l'objet str.
La classe String va donc allouer de la mémoire pour stocker la chaine de caractère qui est contenue dans l'objet temporaire, puis copier les caractères.
Une fois la copie effectue, l'objet temporaire n'est plus utile donc il est détruit.
Bref :
Un meilleur code est tout simplement :
String str = "chaine initiale";
Qui ne fait que l'allocation de str et une seule copie.
Voilà pourquoi je considère qu'utiliser String c'est MAL ]
Quand on est débutant et qu'on ne comprend pas trop les mécanismes qui sont derrière, les programmes plantent sans qu'on sache pourquoi : que croyez vous qu'il se passe si String essaye de redimensionner l'espace de stockage allouée à une String et qu'il n'y a plus de mémoire dispo : rien et le programme part dans les choux.
Sur un PC avec la mémoire virtuelle, peut de chance que cela arrive, mais au pire vous avez une jolie boite de dialogue : "Cette application s'est inopinément arretée : Pas assez de mémoire"
Malheureusement c'est quand on est débutant qu'on se laisse tenté par la facilité d'utilisation de String...
Par ailleurs sur PC, les classes String équivalents sont bien codées. On utilise ce genre de classe avec du try/catch pour pouvoir intercepter les exceptions. Ce qui n'est pas possible avec la classe String Arduino car les codeurs (ah ces artistes) ont allègrement oublié de lever des exceptions en cas d'erreur, se contentant de ne rien faire.
Sur un système à faible ressource mémoire tel qu'un ATmega, il vaut beaucoup mieux apprendre à gérer sa mémoire proprement en sachant ce que l'on fait plutôt que de laisser du mauvais code le faire dans son dos. A terme vous aurez des programmes plus fiables et plus économes en mémoire.
C'était la minute du Professeur Rollin XD
Très bonnes indications !
Justement je vais priofiter de ton cours pour rebondir. La mauvaise habitude que j'ai eu avec les String m'est resté Honte à moi !
Donc vers quelle type de variable s'orienté au niveau du final ?
Je demande car e viens de changer un peu la donne. En fait je vais me permettre de simplifier un peu tout ça.
Mon vichier va évoluer comme suit:
//Modèle
Robot Go//Type
Robot//Mix_V1V2 / Mix_V3V4
true
false
Par contre, au retour j'obtiens:
Robot Go
Robot
fals
false
Il manque un true et j'obtiens un false incomplet qui prends la place du true
Au niveau code quelques changements pour essayer. Tant que j'en suis à tester, autant que je teste toutes les solutions avant de me jetter dans une version finale.
#define SIZE_CONF 10 //Nombre de configuration par fichier
File myFile; //Fichier
String tblFicMdle[SIZE_MODELE]; //Le tableau des noms des fichiers modèles
String tblFicSvg[SIZE_MODELE]; //Le tableau des noms des fichiers de sauvegardes
int nbFichierMdle; //Nombre de fichier
/* SETUP */
void setup() {
//Initialiser la carte SD
if(initSD()) {
//Lister les fichier de sauvegardes
listeFichier("/svgde/");
//Lister les fichiers de configuration modèle
nbFichierMdle = listeFichier("/modeles/");
//Ouvrir le fichier de sauvegarde
//ouvrirFichier("/svgde/", tblFicSvg[0]);
ouvrirFichier("/modeles/", tblFicMdle[2]);
}
}
else {
//Charger les valeurs par défaut de la radio
}
/* FONCTION listerFichier() */
int listeFichier(String chemin) {
int count = 0;
char path[SIZE_BUFFER];
//Conversion du chemin
chemin.toCharArray(path, SIZE_BUFFER);
//Ouvre ce qui est défini par le chemin
myFile = SD.open(path);
//Tant que c'est vrai
while(true) {
//Prend le nom du fichier
File entry = myFile.openNextFile();
//Si c'est la fin
if(!entry) {
break; //Sortir de la boucle
}
//Si le nombre de fichier est plus important que le nombre de place en tableau
if(count == SIZE_MODELE) {
break; //Sortir de la boucle
}
//Si c'est le répertoire /modeles/
if(chemin == "/modeles/") {
//Rentre le nom de fichier dans le tableau des noms de modèles
tblFicMdle[count] = entry.name();
}
//Si c'est le répertoire /sauvegarde/
if(chemin == "/svgde/") {
//Rentre le nom de fichier dans le tableau des noms de sauvegarde
tblFicSvg[count] = entry.name();
}
count++; //Compter le nombre de fichier
}
//Fermer le fichier
myFile.close();
//Retourner le nombre de fichier
return count;
}
/* FONCTION qui ouvre un fichier */
void ouvrirFichier(String chemin, String fic) {
//Variables
char path[SIZE_BUFFER], bufferConf[SIZE_BUFFER];
int i, bufferLenght, lineCounter = 0;
String toto[SIZE_CONF];
clearLcd(); //Efface l'écran
ecrireLcd("Fichier en lecture", 01); //Ecrire
//Crée le chemin
chemin = chemin + fic;
//Transforme le chemin
chemin.toCharArray(path, SIZE_BUFFER);
//Ouvre le fichier
myFile = SD.open(path, FILE_READ);
//Si le fichier est présent
if(myFile) {
//Tant que ce n'est pas la fin du fichier
while(myFile.available()) {
//Récupère la ligne
i = 0;
while((bufferConf[i++] = myFile.read()) != '\n') {
//Si la ligne dépasse le buffer
if(i == SIZE_BUFFER) {
//Finir la ligne et stopper la lecture
while(myFile.read() != '\n') {
break;
}
}
}
bufferLenght = i; //Garder en mémoire le nombre de lettre
bufferConf[--i] = '\0'; //Finir la ligne en retirant le saut de ligne
//Serial.println(bufferConf[0]);
//Ne pas enregistrer les lignes vides ou les commentaires
if(bufferConf[0] == '\0' || bufferConf[0] == '/' || bufferConf[0] == '#') {
continue;
}
toto[lineCounter] = bufferConf;
++lineCounter; //Compter le nombre de lignes
}
Serial.println(path);
Serial.println(toto[0]);
Serial.println(toto[1]);
Serial.println(toto[2]);
Serial.println(toto[3]);
Serial.println(toto[4]);
Serial.println(toto[5]);
Serial.println(lineCounter);
}
else {
clearLcd(); //Efface l'écran
ecrireLcd("Fichier introuvable", 01); //Ecrire
for(;;);
}
//Fermer le fichier
myFile.close();
ecrireLcd("Fichier Ok", 01); //Ecrire
delay(1000);
}
Comme on le voie, si j'ai un commentaire, on saute, si j'ai un saut de ligne on saute.
Ne pas tenir compte de la sortie car je demande plus haut vers quoi je devrais évolué pour ne pas forcément utilisé un String
Merci.
De mon point de vue, il vaut mieux utiliser des tableaux de char, de dimensions connues et maitrisées.
Utiliser les bonnes fonctions telles que strncpy() au lieu de strcpy() etc ... afin d'éviter les débordements de tableaux.
A la fin tu verra que finalement, les tableaux de char et la libC (stdio.h et string.h) offrent beaucoup de possibilités et un meilleur contrôle.
Bon j'ai un autre problème
A prori je ne sort jamais de la boucle while(myFile.available()) {}
Même quand elle ne contient rien !!
Bon j'ai trouvé !
Effectivement pas bon les Strings mais pas bon du tout
Bon, alors j'ai modifier mon code ainsi (et je ne vous met pas tout car c'est que la fin qui change !
/* FONCTION initSD() */
boolean initSD() {
clearLcd(); //Effacer l'écran
ecrireLcd("Init SD Card", 01); //Ecrire
//Si la carte n'est pas présente ou qu'elle est en défaut
if(!SD.begin(4)) {
ecrireLcd("Non presente", 21); //Ecrire
return false;
}
ecrireLcd("Sd card... Ok", 21); //Ecrire
delay(1000);
return true;
}
/* FONCTION listerFichier() */
int listeFichier(String chemin) {
int count = 0;
char path[SIZE_BUFFER];
//Conversion du chemin
chemin.toCharArray(path, SIZE_BUFFER);
//Ouvre ce qui est défini par le chemin
myFile = SD.open(path);
//Tant que c'est vrai
while(true) {
//Prend le nom du fichier
File entry = myFile.openNextFile();
//Si c'est la fin
if(!entry) {
break; //Sortir de la boucle
}
//Si le nombre de fichier est plus important que le nombre de place en tableau
if(count == SIZE_MODELE) {
break; //Sortir de la boucle
}
//Si c'est le répertoire /modeles/
if(chemin == "/modeles/") {
//Rentre le nom de fichier dans le tableau des noms de modèles
tblFicMdle[count] = entry.name();
}
//Si c'est le répertoire /sauvegarde/
if(chemin == "/svgde/") {
//Rentre le nom de fichier dans le tableau des noms de sauvegarde
tblFicSvg[count] = entry.name();
}
count++; //Compter le nombre de fichier
}
//Fermer le fichier
myFile.close();
//Retourner le nombre de fichier
return count;
}
/* FONCTION qui ouvre un fichier */
void ouvrirFichier(String chemin, String fic) {
//Variables
char path[SIZE_BUFFER], bufferConf[SIZE_BUFFER];
int i, bufferLenght, lineCounter = 0;
clearLcd(); //Efface l'écran
ecrireLcd("Fichier en lecture", 01); //Ecrire
//Crée le chemin
chemin = chemin + fic;
//Transforme le chemin
chemin.toCharArray(path, SIZE_BUFFER);
//Ouvre le fichier
myFile = SD.open(path, FILE_READ);
//Si le fichier est présent
if(myFile) {
//Tant que ce n'est pas la fin du fichier
while(myFile.available()) {
//Récupère la ligne
i = 0;
while((bufferConf[i++] = myFile.read()) != '\n') {
//Si la ligne dépasse le buffer
if(i == SIZE_BUFFER) {
break;
}
}
bufferLenght = i; //Garder en mémoire le nombre de lettre
bufferConf[--i] = '\0'; //Finir la ligne en retirant le saut de ligne
lineCounter++; //Compter le nombre de lignes
//Ne pas enregistrer les lignes vides ou les commentaires
if(bufferConf[0] == '\0' || bufferConf[0] == '/' || bufferConf[0] == '#') {
continue;
}
Serial.println(bufferConf);
}
//Fermer le fichier
myFile.close();
}
return;
}
la ou je sort mon Serial.println(bufferConf); c'est là que je dois entrée en tableau. Ce que je cherche c'est à avoir
tbl[0] -> Robot Go
tbl[1] -> Robot
tbl[2] -> true
tbl[3] -> false
Il y aura des tests sur true et false au final. Donc c'est un point à étudier afin de ne pas le perdre de vue.