IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Arduino Discussion :

Print avec un tableau de char mais pas depuis le 1ier caractère


Sujet :

Arduino

  1. #1
    Membre éprouvé Avatar de electroremy
    Homme Profil pro
    Ingénieur sécurité
    Inscrit en
    Juin 2007
    Messages
    934
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 934
    Points : 1 274
    Points
    1 274
    Par défaut Print avec un tableau de char mais pas depuis le 1ier caractère
    Bonjour,

    Le titre alambiqué du sujet mérite plus ample explications...

    J'ai un buffer qui contient des données, parmi lesquelles une ou plusieurs chaines de caractères, chacune terminée par le caractère null

    J'aimerais imprimer ces chaines directement avec print(), sans passer par un buffer intermédiaire

    Exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    #define Buffer_RAM_Len 256
    char Buffer_RAM[Buffer_RAM_Len];
    Mon code remplit le buffer, par exemple il contient : ABCDEFIJKLMNOP suivi d'un octet null

    Je peux faire :
    ce qui va imprimer "ABCDEFIJKLMNOP".

    Mais je voudrais faire tft.print(Buffer_RAM[5]) pour imprimer "FIJKLMNOP".

    Évidemment, tft.print(Buffer_RAM[5]) va imprimer juste le caractère "F"

    Mais je pense que vous avez compris ce que je souhaite faire.

    Mon but est d'économiser la mémoire RAM...

    Ma variable Buffer_RAM[]va contenir des instructions et des données selon un format "maison" que mon programme Arduino va parcourir et interpréter.

    Buffer_RAM[] peut contenir une ou plusieurs chaines de caractères, de longueurs variables.

    Je voudrais :
    - éviter de créer un buffer temporaire pour contenir la chaîne de caractères à afficher.
    - éviter de faire de multiples print() caractère par caractère avec une boucle for...next

    Je pense qu'on peut, en bidouillant un peu salement avec un pointeur (mais c'est de l'embarqué on a le droit aux optimisations un peu barbares ) définir une variable (ou un pointeur) Buffer_Temp[] en lui donnant comme adresse l'emplacement du début de la chaîne dans Buffer_RAM[].
    L'instruction TFT.Print(Buffer_Temp) ne verra que du feu et va sagement imprimer la chaîne à partir de l'adresse de Buffer_Temp[] et jusqu'à l'octet null servant de délimiteur.

    Merci

    A bientôt
    Quand deux personnes échangent un euro, chacun repart avec un euro.
    Quand deux personnes échangent une idée, chacun repart avec deux idées.

  2. #2
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 711
    Points : 5 390
    Points
    5 390
    Par défaut
    Effectivement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    tft.print(Buffer_RAM[5]);
    imprime juste un caractère puisque le type de ce qui est entre parenthèse est un caractère


    Si vous voulez la chaîne, il faut à passer un pointeur sur le début de la chaîne. Le nom du tableau étant un pointeur sur le premier caractère on peut écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    tft.print(Buffer_RAM+5); // pointeur 5 char plus loin
    ou alors demander l’adresse de ce fameux 5ème caractère
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    tft.print(&(Buffer_RAM[5]));
    Dans les deux cas le type de données passé en paramètre est pointeur sur caractère et donc la fonction retenue sera celle qui imprime une cString (tableau de char terminé par ‘\0’)

    Et jouer avec les pointeurs ce n’est pas sale

  3. #3
    Expert éminent sénior
    Avatar de Auteur
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    7 648
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 7 648
    Points : 11 137
    Points
    11 137
    Par défaut
    Bonjour,

    un exemple avec strtok. Mais pas sûr que cela convienne, strtok prend en paramètre également une expression régulière pour indiquer comment séparer les différents éléments de la chaîne.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    char *pch;
    char buf[9];  // taille du buffer de lecture (max 9 caractères).
    byte n;
    String str1, str2;
     
    // format de la chaine reçue : xxx,xxxx\n
    n = Serial.readBytesUntil('\n', buf, 9);    // Lecture de 9 caractères se terminant par \n et placés dans le tableau buf
     
    pch = strtok(buf, ",");
    str1 = pch;
     
    pch = strtok(NULL, ",");
    str2 = pch;
     
    Serial.println(str1);
    Serial.println(str2);

  4. #4
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 711
    Points : 5 390
    Points
    5 390
    Par défaut
    Salut

    Votre exemple est interessant mais il duplique de la mémoire (en plus dans un objet String qui est gourmand) et oublie que readBytesUntil() ne rajoute pas un ‘\0’ à la fin de la chaîne (ça marche si vous rentrez moins de 9 caractères parce que la variable globale est initialisée avec des 0)

    Comme @electroremy veut économiser de la mémoire, on peut simplement se souvenir que strtok ne fait que mettre un caractère nul (finissant donc une cString) à la place du séparateur trouvé.

    On a donc qu’à déclarer des pointeurs sur caractère (qui pointeront au sein du buffer) pour mémoriser les différents points de départ des 2 chaînes

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    char buf[10];  // taille du buffer de lecture (max 9 caractères plus le caractère nul).
    size_t n;
    char *str1, *str2;  // pointeurs au sein de buf
    
    // format de la chaine reçue : xxx,xxx\n
    n=Serial.readBytesUntil('\n', buf, 9);    // Lecture de max 9 caractères se terminant par \n et placés dans le tableau buf
    buf[n]='\0'; // on termine correctement la cString
    
    str1 = strtok(buf, ","); // pointeur sur début de chaîne, même adresse que buf
    str2 = strtok(NULL, ","); // pointeur au sein de buf sur le caractère suivant la virgule
    
    Serial.println(str1);
    Serial.println(str2);

  5. #5
    Expert éminent sénior
    Avatar de Auteur
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    7 648
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 7 648
    Points : 11 137
    Points
    11 137
    Par défaut
    Oui ce n'est qu'après avoir posté le message que je me suis rendu compte que cela ne répondait pas vraiment à la question. Ensuite, la méthode est assez contraignante car la chaîne doit respecter scrupuleusement le format indiqué.

  6. #6
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 711
    Points : 5 390
    Points
    5 390
    Par défaut
    Oui faudrait tester le pointeur retourné, s’il est nul c’est que strtok() n’a pas trouvé la virgule

  7. #7
    Membre éprouvé Avatar de electroremy
    Homme Profil pro
    Ingénieur sécurité
    Inscrit en
    Juin 2007
    Messages
    934
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 934
    Points : 1 274
    Points
    1 274
    Par défaut
    Bonjour,

    Citation Envoyé par Jay M Voir le message
    Si vous voulez la chaîne, il faut à passer un pointeur sur le début de la chaîne. Le nom du tableau étant un pointeur sur le premier caractère on peut écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    tft.print(Buffer_RAM+5);
    C'est simple et (presque) évident.

    Je viens de tester, ça fonctionne.

    Comme expliqué, il faut être sûr qu'il y a un bien un octet null dans le buffer pour finir la chaîne dans les données qui suivent l'adresse, sinon Print() va parcourir toute la mémoire et s'il ne trouve pas d'octet null ça risque de planter.

    Merci

    A bientôt
    Quand deux personnes échangent un euro, chacun repart avec un euro.
    Quand deux personnes échangent une idée, chacun repart avec deux idées.

  8. #8
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 711
    Points : 5 390
    Points
    5 390
    Par défaut
    Oui il faut être sûr de rester au sein du buffer.

    Une technique c’est de déclarer un buffer avec par exemple 11 cases, de mettre un zéro à l’index 10 (à la fin du tableau) et partout où vous l’utilisez de faire comme si vous n’aviez que 10 cases de dispo. Comme ça vous ne déborderez pas

    On peut aussi bien sûr tester si le pointeur avec lequel on joue est entre le début et la fin du buffer
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    const byte tailleBuffer = 10; // taille utilisable
    char buffer[tailleBuffer+1]; // +1 pour le caractère nul
    char *ptr;
    ...
    buffer[tailleBuffer] = ’\0’; // en protection on aura toujours une cString comme ça
    
    // si le pointeur est non NULL 
    // et s’il pointe au sein du buffer 
    // et si son contenu n’est pas ’\0’
    if (ptr && (ptr >= buffer) && (ptr <= buffer + sizeof(buffer)) && *ptr) {
    ...
    }
    Là on est ceinture bretelle

  9. #9
    Membre éprouvé Avatar de electroremy
    Homme Profil pro
    Ingénieur sécurité
    Inscrit en
    Juin 2007
    Messages
    934
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 934
    Points : 1 274
    Points
    1 274
    Par défaut
    Bonjour,

    En effet il faut des tests !

    La quantité de tests dépendra certainement... de la quantité de ROM restante une fois le programme terminé

    Sachant que mon système final (projet domotique) sera presque complètement "fermé" : ce sont mes Arduinos "clients" qui vont communiquer avec un Arduino "Serveur", en HTTP avec TCP/IP

    L'ensemble est programmé par mes soins.

    Tout sera installé chez moi, en étant relié via des câbles Ethernet sur un switch.

    Chaque client ainsi que le serveur aura une IP fixe.

    La couche TCP/IP est sûre donc à priori pas de risque de recevoir des données altérées ou tronquées.

    Les tests ne servirons qu'à fiabiliser le système en cas de bug. Je n'ai pas besoin, dans mon projet, de garantir un comportement fiable face à des saisies erronées ou malveillantes d'appareils tiers ou d'utilisateurs humains, ou encore de perturbations Wifi, ce qui est un gros avantage.

    Les développeurs qui programment des applications serveurs accessibles librement sur le net ont énormément de choses à vérifier.
    Le fameux internet des objets me semble être une grosse passoire

    Le serveur aura tout de même besoin de communiquer avec d'autres appareils sur le réseau local... cette partie là devra être fiabilisée au maximum, car ces autres appareils sont susceptibles d'envoyer n'importe quoi au serveur.

    Bonne nouvelle, dans mon projet, c'est les clients qui vont recevoir beaucoup de données, et là pas trop de soucis car il n'y a que MON serveur qui va leur envoyer des données.

    Il est facile, dans le code des clients, de sécuriser la communication :
    - en authentifiant le serveur avant de traiter les données : en plus de l'adresse IP, vérifier la présence d'une petite "clef", qui peut être "tournante" c'est à dire différente à chaque envoi, il suffit simplement de calculer la clef à partir des données de la requête envoyée par le client
    - de vérifier les données, un CRC sur un octet suffit pour détecter la plupart des erreurs (il faudrait ne pas avoir de chance pour tomber sur un nombre pair d'erreurs sur le même bit)

    J’envisage en plus, pour les clients et le serveur, un chien de garde matériel (si une broche ne change pas d'état régulièrement, un monostable force le reset)
    Cela me semble vraiment indispensable pour un projet embarqué. Un bug peut facilement bloquer le microcontrôleur dans une boucle infinie.

    Et également des sécurités "analogiques" en aval des sorties pilotées par le serveur :
    - thermostat mécanique de sécurité pour une température mini et maxi
    - monostables (minuteries) pour éteindre les appareils qui ne sont pas censés fonctionner longtemps, dans le cas de figure où la sortie resterait bloquée sur "on".

    Ces sécurités analogiques permettent surtout de se prémunir contre une défaillance du hardware. Les produits electro-informatiques miniaturisés à l'extrême sont fragiles, on a tendance à oublier cet aspect. Le meilleur des logiciels ne peut rien faire si une broche d'entrée/sortie lâche et se met en court circuit à la masse ou à +Vcc.

    A bientôt
    Quand deux personnes échangent un euro, chacun repart avec un euro.
    Quand deux personnes échangent une idée, chacun repart avec deux idées.

  10. #10
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 711
    Points : 5 390
    Points
    5 390
    Par défaut
    Beau projet !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Pb avec un tableau, insert ne fonctionne pas mais requete OK.
    Par franco14 dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 16/04/2010, 11h31
  2. [PHP 5.2] Realpath fonctionne avec le navigateur d'eclipse mais pas firefox
    Par Polymorph dans le forum Langage
    Réponses: 1
    Dernier message: 09/03/2009, 08h50
  3. Réponses: 2
    Dernier message: 24/07/2007, 20h16
  4. Test OK avec maven 2.0.4, mais pas avec 2.0.6 ni 2.0.7
    Par gifffftane dans le forum Maven
    Réponses: 6
    Dernier message: 03/07/2007, 14h58
  5. Réponses: 1
    Dernier message: 08/11/2006, 21h14

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo