Pourquoi mon sérial ne lit que 71 caracteres

Bonjour,
Je me casse les pieds méchament depuis deux jours sur la lecture de SMS.

J'ai une fonction qui fait

  • lire la réponse de la commande AT+CMGR
  • stoque la réponse dans un buffer d'une taille de 200 : char buffer[200];
  • Supprime des carateres comme les ", les \n et \r
  • Met chaque ligne dans un tableau pour avoir la premiere ligne dans response[1], la deuxieme dans response[2], etc...

Ce qu'il se passe, c'est quand j'ai "une grande réponse" il me tronque le résultat et le OK n'est pas présent.

J'ai aussi imprimé avec un Serial.println(x) pour suivre l'index. Et ce qu'il me surprend c'est qu'après env 71 cavatere lu du serial ( char r = _cell.read();), le sérial n'est plus available.

J'aimerais savoir si vous pouviez m'aider à relire ma fonction et essayer de comprendre le _cell.read() n'affiche pas toute la réponse.

Je vais bien commenter mon code que voici:
Elle est longue, mais je pense que c'est bien commenter pour vite comprendre
(voir le fichier attaché, s'il est mal lisible, je créerai un lien externe)

Le problème que j'ai c'est que mes réponse ne sont pas terminée.

Le meilleur exemple, est quad j'essaye d'avoir la position des CellID avec la commande
AT+CENG?

Voici la réponse en mauvaise état_

AT+CENG?
+CENG: 3,0
+CENG:0,228,02,1388,147d,15,10
+CENG:1,000,00,0000,0000,00, 6
+CE20,,0000
EG0,00,00,
CG,00000,,
+G500000001+E60,,00001
O

Alors qu'elle devrait resembler à un truc du genre

AT+CENG?
+CENG: 3,0
+CENG:0,228,02,1388,147d,15,10
+CENG:1,000,00,0000,0000,00, 6
+CENG:2,000,00,0000,0000,00, 6
+CENG:3,000,00,0000,0000,00, 6
+CENG:4,000,00,0000,0000,00, 6
OK

Je n'arrive pas à comprendre pourquoi.
Dans ma fontion si dessus, j'ai mis ceci:

Serial.print(x);
          Serial.print(F(":"));
          Serial.println(buffer[x]);

Et je suis surpris qu'il s'arrete à 73 alors que si je colle la réponse en mauvais état dans word, il
m'indique 130 caracters et la variable buffer en accepte 200.

Si je décommnet ceci

//Serial.println(F("N/A"));
        //Serial.println(x);

Il m'affiche plein de N/A après le 73eme caractere alors qu'il y en a encore 57 à afficher

Comprenez-vous pourquoi?
J'ai aussi constater que le problème vient avec mon switch(r).
Es-ce ma fonction est boiteuse?

Milles mercis pour votre précieuse aide. ...Et pour votre passé sur mon problème

code.txt (6.58 KB)

Je viens de lire un truc qui pourrait répondre à ma question

Get the number of bytes (characters) available for reading from the serial port. This is data that's already arrived and stored in the serial receive buffer (which holds 64 bytes). available() inherits from the Stream utility class.

Si je comprends bien et excusez-moi pour mon côté novice, le serial ne peut que contenir que 64 carcartere?
Donc si ma réponse depasse ceci, ca casse?

Je suis un peu surpris, car j'avais réussi à avoir toute ma reponse de la commande AT+CENG?
Je suis un perdu... :o)

Non?

Si c'est le cas, comment je peux recupérer une réponse qui a plus de 64 carcateres alors?

Salut
Tu utilises quel type de port série ?
Matériel ou logiciel ?
J'ai le même genre de soucis avec un ESP8266 (wifi) sur un port série logiciel.

heu, que veux tu dire?
J'ai un arduino Mini pro et j'utilise les pin 10 et 11.
Genre:

SoftwareSerial _cell(10, 11);  //rx, tx

Sauf que dans mon cas, je le déclare dans mon constructeur

WI968C::WI968C(bool debug):_cell(10,11)// RX / TX
{
  if(debug)
  {
    #define DEBUG
  }

}

Tu utilises bien un port série logiciel.
Softwareserial émule un port série sur les pins 10 et 11.
Il y a une astuce pour augmenter le buffer de Softwareserial en modifiant un fichier .h.
J'ai fait de nombreux tests sans trouver de solution.
Le port série matériel (pins 0 et 1) est plus fiable, mais tu ne peux plus debugger....
Donc il vaut mieux utiliser une carte avec deux ports série matériels.
Je ne comprends pas tous ces exemples de codes qui utilisent Softwareserial, alors ça ne marche pas très bien.
Ou alors, il y a un truc qu'on a pas compris.

Il y a un jeu entre les buffer, leur taille et la disponibilité du CPU. La taille des buffer est réglables dans les deux cas (hardwareSerial.h pour le hard et SoftwareSerial.cpp pour le soft de mémoire).

Si l'émission est plus longue que la réception alors le buffer se remplit et dégueule au bout d'un moment. En plus sur le soft il y a une utilisation d'interruption et elle peuvent interférer avec celle du port série hard par exemple.

Pour éliminer certains problèmes : avoir un buffer large, avoir une chaine de stockage large (bien penser à l'initialisé avec un memset(,NULL,), ça m'a éviter pas mal de soucis perso ...) et "libérer" le CPU pendant la réception (un delay() suffit).

pierrot10:

WI968C::WI968C(bool debug):_cell(10,11)// RX / TX

{
  if(debug)
  {
    #define DEBUG
  }

}

DEBUG sera toujours défini, ne pas confondre directive préprocesseur et variable.

Salut B@atto

Merci pour ta réponse mais j'ai pas tout compris.
Comment on fait pour augmenter les 64byte?
Sur mon Mac j'ai fait une recherche sur le mot SoftwareSerial.cpp et il ne trouve rien.
Idem pour HardwareSerial

Em ce qui cocnerne mon buffer, soit la variable char buffer[200], qui stock les caracteres recu, elle est assez grande pour receoir les 130 carcatere sans qu'elle explose

Oui mais le buffer est à 64 :wink:

SoftwareSerial est dans le dossier librairie, HardwareSerial dans le dossier core :

Soft :

https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/libraries/SoftwareSerial/SoftwareSerial.h

Voir :

#define _SS_MAX_RX_BUFF 64 // RX buffer size

Hard :

https://github.com/arduino/Arduino/tree/master/hardware/arduino/avr/cores/arduino

Partie intéressante :

#if !defined(SERIAL_TX_BUFFER_SIZE)
#if (RAMEND < 1000)
#define SERIAL_TX_BUFFER_SIZE 16
#else
#define SERIAL_TX_BUFFER_SIZE 64  // taille buffer de transmission si quantité de RAM >1000 bytes
#endif
#endif
#if !defined(SERIAL_RX_BUFFER_SIZE)
#if (RAMEND < 1000)
#define SERIAL_RX_BUFFER_SIZE 16
#else
#define SERIAL_RX_BUFFER_SIZE 64  // taille buffer de réception si quantité de RAM >1000 bytes
#endif
#endif

Salut B@tto,
je te remercie. Ces lignes me parlent et c'est bien ce que je cherchais.

Maistenant j'ai une derniere question. Avant mon précédent post, j'étais allé voir dans le dossier Librairies et je viens d'y aller. Je ne trouve pas ce ficher!!! (je suis sous Mac)

Es-ce qu'il ne s'agit pas du SoftwareSerial qui est inclu dans l'IDE Arduino?

Si non, est ce que je devrais alors copier le lien Github que tu as mis, dans le dossier librairire et ajouter
#include SoftwareSerial dans mon .cpp?

Puis ensuite chercher les lignes
#define _SS_MAX_RX_BUFF 64 // RX buffer size

Es-ce que je peux monter sans autre, à 128?

J'ai aussi ajouter un delay(100) ici

do{
      // If _cell is available
      if(_cell.available() > 0)
      {
        //sprint(F("BUFFERSIZE:")); Serial.print(x), sprint(F("/")); Serial.println(BUFFERSIZE);
        // This is a security in case of the number of caraters of the response is larger than the buffer size
        if(x < BUFFERSIZE-1) 
        {
          // Read the caracters of the response, one by one
          char r = _cell.read();
          //char r = (_cell.read());

          delay(100);

.... suite du code ---
}while{...}

mais jai pu encore tester

Tes problème sont causés par un débordement du buffer de réception. L'augmentation de la taille du buffer de réception ne fait souvent que déplacer le problème jusqu'à ce que tu rencontres un cas de chaine un peu plus longue. En plus cela monopolise de la RAM sur un processeur qui n'en a pas beaucoup.
Plutôt que d'augmenter la taille du buffer de réception je pense qu'il serait plus pertinent d'optimiser la réception des données.
L'UART logiciel consomme pas mal de ressource. Donc il faut éviter de dérouler beaucoup de code pendant la phase de réception. Le filtrage des caractères à la volée qui a du sens dans le cas d'une UART matériel n'est dans ce cas pas une bonne idée. Il vaudrait mieux te contenter de stocker les caractères reçus dans ton buffer de réception et de faire le filtrage ultérieurement.

Pour moi, la meilleur solution est d'utiliser le port matériel pour ce genre de problème.
L'affirmation de tahitibob35 à mon sens n'est pas justifiée

Le port série matériel (pins 0 et 1) est plus fiable, mais tu ne peux plus debugger....

La finalité de l'objet n'est pas le debug mais la lecture de SMS. Donc il faut mettre l'interface performante sur ce sujet. Tu peux toujours utiliser une UART logiciel pour le debug qui justement ne sera plus nécessaire au final.

Salut fdufnews,

J'arrive pas trop cerner ce que tu veux dire mais si je comprends le sense. Peut etre que c'est des termes techniques qui me brouille.

Tes problème sont causés par un débordement du buffer de réception

.

Que veux tu dire par buffer de reception?
J'ai un variable de type char

char buffer[200];

voir mon fichier attaché, code.txt)
Dans ce buffer, je stock mes caractères réceptionnés

char r = _cell.read();
buffer[x++] = r

Quand tu parles de buffer de réception, es-ce que cette varaible qui srock la reception?
Parceque là, je ne pense pase que c'est le problème, dans ce cas précis, car elle fait 200 et j'attends 130 caractere.

Plutôt que d'augmenter la taille du buffer de réception je pense qu'il serait plus pertinent d'optimiser la réception des données.

Ok,je suis d'accord avec ca, je n'aurais jamais une réponse plus grande que celle ci

AT+CENG?
+CENG: 3,0
+CENG:0,228,02,1388,147d,15,10
+CENG:1,000,00,0000,0000,00, 6
+CENG:2,000,00,0000,0000,00, 6
+CENG:3,000,00,0000,0000,00, 6
+CENG:4,000,00,0000,0000,00, 6
OK

et je dois arriver à optimiser la réception pour pour exploiter ceci

+CENG:0,228,02,1388,147d,15,10
+CENG:1,000,00,0000,0000,00, 6
+CENG:2,000,00,0000,0000,00, 6
+CENG:3,000,00,0000,0000,00, 6
+CENG:4,000,00,0000,0000,00, 6

et au minimum les trois premier

+CENG:0,228,02,1388,147d,15,10
+CENG:1,000,00,0000,0000,00, 6
+CENG:2,000,00,0000,0000,00, 6

Le buffer de réception, c'est celui dont parlait B@tto. C'est le buffer qui est instancié par la librairie SoftwareSerial et qui fait 64 caractères.
Ce buffer stocke les caractères qui ont été reçus et qui ne sont pas encore lus. Si ce buffer déborde c'est que tu ne lis pas assez vite les caractères reçus d'ou ma suggestion de limiter la charge du processeur lors de la réception afin de relire plus vite ces données.

Donc il faudrait que mon serial soit à 115200 au lieu de 9600?

Pas que : si tu es trop lent à vider le buffer hard ou soft pour une raison x ou y (tu fais une action à ce moment la) tu auras le même problème.

Pour t'éclaircir les idées : que ce soit en hard ou en soft, il y a un buffer qui permet de stocker les données arrivant à n'importe quel moment. C'est hyper important, si c'était pas le cas, il faudrait être "à l'écoute" en permanence du port pour ne pas perdre de donnée. Donc ce buffer la, tu le règle dans la lib comme je l'ai indiqué. Mais ce buffer, tu n'y a pas accès "comme ça", tu ne le vides qu'en utilisant read(), et tu remplies alors généralement un tableau de char sur lequel tu travailleras ensuite.

Dans ton code je vois un delay(100), c'est très problématique, en 100 ms tout est arrivé en fait. Une routine comme ça devrait fonctionner sans changer la taille du buffer, et à condition de ne pas écouter trop tard (si dans ta loop() par exemple il y a un delay(500) et que la communication arrive à ce moment la alors tu l'as dans l'os ...).

void loop() {

if(Serial.available()) {

static char buf[200];
static int i=0;

while(Serial.available()) buf[i++]=Serial.read();

if(buf[i]=='\n') {
i=0;
memset(buf,NULL,sizeof(buf));

traitement();
}

}

}

En dehors du if, tu as moins de 64*1/9600= 6,6 milliseconde pour effectuer une autre action si tu ne veux pas perdre de données

Voici une sujet intéresanr que j'ai trouvé

With some sketches, the buffer of the UART may be small, to increase the length of the buffer you need to change these lines in the file HardwareSerial.h in /arduino-1.0.X/hardware/arduino/avr/cores/arduino/ (or in file HardwareSerial.cpp in /arduino-1.0.X/hardware/arduino/cores/arduino/ depending on the Arduino IDE version)

change

#if (RAMEND < 1000)
#define SERIAL_TX_BUFFER_SIZE 16
#define SERIAL_RX_BUFFER_SIZE 16
#else
#define SERIAL_TX_BUFFER_SIZE 64
#define SERIAL_RX_BUFFER_SIZE 64
#endif
#endif

to

#if (RAMEND < 1000)
#define SERIAL_TX_BUFFER_SIZE 400
#define SERIAL_RX_BUFFER_SIZE 400
#else
#define SERIAL_TX_BUFFER_SIZE 400
#define SERIAL_RX_BUFFER_SIZE 400
#endif
#endif

https://www.cooking-hacks.com/documentation/tutorials/gprs-gsm-quadband-module-arduino-raspberry-pi-tutorial-sim-900

Bin ouais c'est que je t'ai mis plus haut ^^

Mais bon la tu bouffes presque la moitié de la RAM dans les buffers série ...

Attention aussi que si tu réalises d'autres projets ensuite, bien penser à remettre des valeurs "normales"