Go Down

Topic: Carte SD - programmation [mettre en tableau key et val liées] - config.txt (Read 3 times) previous topic - next topic

Microbulle

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 !

SesechXP

Tout simplement avec le constructeur de la classe String :
Code: [Select]

char* charArray = "Hello world!";
String str = String(charArray);


++

barbudor

Code: [Select]
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 :
- Perte d'efficacité car on copie 2 fois l'ensemble des caractères = perte de temps
- Fragmentation inutile de la mémoire car on alloue pour rien une mémoire temporaire qui est ensuite libérée mais crée un trou dans la zone d'allocation dynamique de mémoire.

Un meilleur code est tout simplement :
Code: [Select]
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

Barbuduino: Arduino sur Breadboard & VinciDuino: Clone Leonardo // WR703: Mini-routeur hacké // LauchPad MSP430 et Stellaris // Panda II Arduino-like .NetMF sous VisualC#
RTFC: Read That F.....g Code / RTFD: Read That F.....g Doc / RTFDS: Read That F.....g DataSheet / RTFS: Read That F.....g Schematic / Wot da ya wanna D.I.Y. today ?

Microbulle

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é  :smiley-mr-green: 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:
Quote

//Modèle
Robot Go

//Type
Robot

//Mix_V1V2 / Mix_V3V4
true
false


Par contre, au retour j'obtiens:
Quote

Robot Go
Robot
fals
false


Il manque un true et j'obtiens un false incomplet qui prends la place du true  :smiley-sad-blue:

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.
Code: [Select]

#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  :smiley-mr-green:

Merci.

barbudor

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.
Barbuduino: Arduino sur Breadboard & VinciDuino: Clone Leonardo // WR703: Mini-routeur hacké // LauchPad MSP430 et Stellaris // Panda II Arduino-like .NetMF sous VisualC#
RTFC: Read That F.....g Code / RTFD: Read That F.....g Doc / RTFDS: Read That F.....g DataSheet / RTFS: Read That F.....g Schematic / Wot da ya wanna D.I.Y. today ?

Go Up