Je souhaite intercepter une chaine de caractères depuis la console série

bonjour à tous,
je cherche à récupérer une adresse ip qui est envoyée sur le port série ex: VarIp=192.168.1.45
Le problème que je rencontre c'est que je suis limité en effet si j’envoie VarIp=192.168.1.45 cela ne fonctionne pas, si j’envoie la même chose sans le 5 (le dernier chiffre) c'est ok.
Merci d'avance pour votre aide :slight_smile:

voici mon code :

String inputString = "";
String ipAddress = "";  // Variable qui contiendra la saisie après "VarIp="

// Fonction pour vérifier si le texte commence par "VarIp"
bool startsWithVarIp(const String& text) {
return text.startsWith("VarIp=");
}

void setup() {
  // Initialize serial communication
  {
    Serial.begin(115200);
    Serial.println("ComVarIp"); 
    delay(200);
}

while (true) {
    // Vérifier si des données sont disponibles dans le port série
    if (Serial.available() > 0) {
      // Lire les données disponibles
      char incomingChar = Serial.read();      
      // Ajouter le caractère à la chaîne d'entrée
      ipAddress += incomingChar;
      // Si le caractère reçu est un saut de ligne ou un retour chariot, on le considère comme une ligne complète
      if (incomingChar == '\n' || incomingChar == '\r') {
        // Enlever les espaces inutiles et trim la chaîne
        ipAddress.trim();        
        // Si la chaîne commence par "VarIp=", on extrait ce qui suit "="
        if (startsWithVarIp(ipAddress)) {
          // Extraire la partie après "VarIp="
          String extractedData = ipAddress.substring(6);  // "VarIp=" fait 6 caractères                 
          Serial.println(F("Commande 'VarIp' détectée. Donnée extraite :"));
          Serial.println(extractedData); 
          Serial.println(F("le script continue !!!!"));         
          break;  // Sortir de la boucle d'attente
        } else {
          // Si la saisie n'est pas "VarIp=", afficher un message et recommencer
          Serial.println(F("Ce n'est pas une commande valide. Essayez encore..."));
          ipAddress = "";  // Réinitialiser la chaîne pour recommencer
        }
      }
    }
  }
}
 
void loop() {

}

J'ai lu l’excellent tuto ici [Ecouter le Port Série ou un keypad (applicable à 1 flux de données asynchrone ) - #3 by J-M-L]
et je pense qu'il faudrait que j'utilise plutôt char que String .... qu'en pensez-vous ?

Merci d'avance.
Cordialement.

pour moi ça fonctionne

Personnellement je pense que ce serait mieux de faire sans les Strings mais ça dépend de la taille de votre code...

Bonjour et merci pour votre réponse rapide cela fait plaisir de se sentir soutenu :slight_smile:

en fait je crois savoir pourquoi :


void setup() {
  // Initialize serial communication
  {
    Serial.begin(115200);
    Serial.println("ComVarIp");
    //delay(200);
    //Serial.println("ComVarListsalons"); 
  }

si je n'envoies qu'une commande Serial.println c'est ok si j'envoie les deux à la suite cela coince :frowning:

De plus, oui en effet, je pense aussi car je suis tendu au niveau mémoire mais je n'ai pas le niveau de dev pour remplacer les String par char ...
Merci encore.

Cordialement.

pas dans le petit exemple que vous donnez et il n'y a aucune raison que ce soit le problème en soi.

C'est peut être un souci mémoire. Si vous faites le test dans votre "gros" code, il se peut en effet qu'il y ait un souci mémoire. Activez tous les warning dans les préférences et regardez aussi combien de RAM il vous reste une fois que vous avez compilé ➜ ça dit quoi ?

un truc simple pour regagner de la RAM, c'est d'utiliser la macro F() dans vos affichages de texte. Au lieu de

    Serial.println("ComVarIp");

faites

    Serial.println(F("ComVarIp"));

➜ remplacer tous les print de texte par cette forme, ça met le texte en mémoire flash au lieu de dupliquer et de l'avoir en flash + RAM.

en effet la cela passe nickel :slight_smile:
Une petite aide pour transformer le string en char dans mon code ne serait pas de refus mais je ne veux pas abuser de votre gentillesse ...
J

Bonjour dimitri67

Pour saisir des paramètres depuis la ligne de commande, c'est plus simple en utilisant la fonction:
ipAddress = Serial.readStringUntil('\n');

Le programme:

String ipAddress = "";  // Variable qui contiendra la saisie après "VarIp="

const int ipAddressLenght = 15;
char ipAddressChar[ipAddressLenght+1]; // IP adresse en char

void setup() {
	// Initialize serial communication
	{
		Serial.begin(115200);
		delay(200);
		Serial.println("ComVarIp");
	}
}

void loop() 
{
	if (Serial.available()) 
	{
		ipAddress = Serial.readStringUntil('\n');
		ipAddress.trim();
		if (ipAddress.startsWith("VarIp="))
		{
			ipAddress.replace("VarIp=", "");  // Supprimer "VarIp="
			ipAddress.toCharArray(ipAddressChar, ipAddress.length() +1);
			Serial.println(F("Commande 'VarIp' détectée. Donnée extraite :")); // IP en char
			Serial.println(ipAddress);
			Serial.println(F("le script continue !!!!"));
		}
		else
		{
			// Si la saisie n'est pas "VarIp=", afficher un message et recommencer
			Serial.println(F("Ce n'est pas une commande valide. Essayez encore..."));
			ipAddress = "";  // Réinitialiser la chaîne pour recommencer
		}
	}

}

Cordialement
jpbbricole

tapé ici, non testé

byte adresseIP[4];

void lireIP() {
  constexpr byte bufferSize = 32;
  char buffer[bufferSize];

  byte index = 0;
  char currentChar;

  while (true) {
    // Lire une ligne terminée par '\n'
    index = 0; // Réinitialiser l'index pour chaque nouvelle lecture
    while (index < bufferSize - 1) {
      if (Serial.available()) {
        currentChar = Serial.read();
        if (currentChar == '\n') break;  // Arrêter la lecture si on atteint un retour à la ligne
        if (!isspace(currentChar)) buffer[index++] = currentChar;  // Ignorer les espaces
      }
    }
    buffer[index] = '\0'; // Terminer la chaîne

    Serial.print("J'ai reçu : "); Serial.println(buffer);

    // Vérifier le format et extraire les octets IP
    int octet1, octet2, octet3, octet4;
    if (sscanf(buffer, "VarIp=%d.%d.%d.%d", &octet1, &octet2, &octet3, &octet4) == 4) {
      // Vérifier que les octets sont dans la plage valide
      if ((octet1 >= 0 && octet1 <= 255) &&
          (octet2 >= 0 && octet2 <= 255) &&
          (octet3 >= 0 && octet3 <= 255) &&
          (octet4 >= 0 && octet4 <= 255)) {
        adresseIP[0] = octet1;
        adresseIP[1] = octet2;
        adresseIP[2] = octet3;
        adresseIP[3] = octet4;
        break; // Quitter la boucle après avoir reçu une adresse IP valide
      }
    } else {
      Serial.println("Format invalide. Réessayez.");
    }
  }
}

void setup() {
  Serial.begin(115200);
  Serial.println("Entrez l'adressse IP.");
  lireIP(); // fonction bloquante
  Serial.print("Adresse IP extraite : ");
  Serial.print(adresseIP[0]);
  Serial.print(".");
  Serial.print(adresseIP[1]);
  Serial.print(".");
  Serial.print(adresseIP[2]);
  Serial.print(".");
  Serial.println(adresseIP[3]);
}

void loop() {}

ça devrait aller extraire l'adresse IP et mettre les valeurs dans le tableau d'octets.
l'appel à la fonction lireIP () est bloquant tant qu'on n'a pas reçu quelque chose de cohérent.

Il y a un petit contrôle de cohérence mais si vous tapez "VarIp=192.168.1.45.coucou" par exemple, ça va fonctionner quand même.

On pourrait faire moins gourmand encore en n'utilisant pas sscanf() et utilisant strncmp() et strtol() mais ça complexifie un peu le code

Bonjour JP,
Merci pour ton aide cela fonctionne bien dans ce cas de figure si je rentre 192.168.1.45
dans le même ordre d'idée je souhaiterai pouvoir intercepter une chaine de caractères qui possède des espaces ex : (67) BOUTIQUE A, (88) BOUTIQUE B et la cela coince, je pense que c'est la fonction .trim tu aurais une idée merci encore :slight_smile: Cordialement.

Si vous voulez étudier comment écouter le port série (ou gérer un flux asynchrone genre keypad) vous pouvez jeter un oeil à mon petit tuto sur le sujet

Il y a une fonction qui écoute le port série jusqu’à la fin de ligne et de façon non bloquante

——

quel code utilisez vous pour cela ?

si vous faites comme @jpbbricole

if (Serial.available()) {
  String laLigne = Serial.readStringUntil('\n');
  ...
}

alors la variable laLigne va contenir ce que vous avez tapé jusqu'au '\n' ou si il y a un timeout parce que le \n n'est pas arrivé assez vite.

Bonjour dimitri67

La fonction trim() n'enlève les espaces qu'au 2 bouts de la chaîne-
Je n'ai pas compris quel est le problème, tu n'arrive pas à saisir une chaîne avec des espaces?

A+
Cordialement
jpbbricole

Bonjour J-M-L

Si l'on utilise un terminal comme le moniteur de l'IDE Arduino ou tout autre émulateur asynchrone, la chaîne introduite n'est pas envoyée caractère aprés caractère (à la volée), mais d'un bloque, en cliquant sur le bouton d'envoi ou usage de la touche Enter, donc pas de problème de vitesse de frappe.
Le seul cas où il peut y avoir un timout sur Serial.readStringUntil, est l'oubli de la terminaison attendue, dans les paramètres du terminal.

Une toute belle journée à vous!
jpbbricole

Merci JML je vais m'attacher à lire ce tuto et apprendre cela évitera les questions un peu trop newbies :slight_smile:

Merci jpbbricole je vais regarder cela
Bonne journée et merci pour votre aide
Belle communauté ici !

Bon je n'y arrive pas avec le VarStock, en fait si j'entre VarStock=TOTO pas de problème, si j'entre VarStock=(54) BOUTIQUE A, cela coince ...
https://wokwi.com/projects/412612328842067969
Merci encore à la communauté pour votre aide :slight_smile:

Oui pour le moniteur série de l’arduino (ce n’est pas envoyé d’un bloc mais à la vitesse en bauds définie avec potentiellement des ralentissements dûs à l’émetteur si par hasard votre PC fait aussi autre chose mais ce n’est généralement pas suffisamment bloquant pour atteindre le timeout par défaut qui est d’une seconde).

Par contre d’autres terminaux peuvent envoyer les touches à la volée et la ce pourrait être un souci.

Les données seront transmises par port usb/serial via un raspberry via node red .

Bonjour dimitri67

OK, mais quel est le problème ?

Mon programme ne supprime pas les espaces dans la chaîne ?

Cordialement
jpbbricole

non les espaces ne sont pas supprimés et c'est le but mais essayes mon script sur wokwi tu verras que la trame VarStock=(XX) BOUTIQUE A ne passe pas ?
Commande 'VarStock' détectée. Donnée extraite :
(55) BOUTIQUE A
VarStock est :

le script continue !!!!

Pour passer de la page 0 à 1 il faut juste entre VarIp=192.111111 etc et le script se poursuit
si l'on entre VarStock=TOTO pas de pb si espace cela coince et je ne l'explique pas ?

Merci pour ton aide

Si tu utilise uniquement le woki, ton problème est celui décrit pas @J-M-L.
Le timeout ce déclenche avant l'arrivé du \n,

A mon avis le mieux serait d'utiliser la façon commune de lire un port série

    while (Serial.available() > 0) {
      incomingChar = Serial.read();  
      VarDatas += incomingChar;
      if (incomingChar == '\n') {
        break;
      }
    }

tu peux aussi garder le readStringUntil mais vérifier que tu as bien tout lu, puisque comme l'indique @J-M-L tu n'a pas de garantit de toujours recevoir la chaine en une seul fois.

Merci Terwal,

Je v charger le code dans l'arduino pour voir :slight_smile: