Go Down

Topic: [Debutant] plantage sur manip string (Read 3912 times) previous topic - next topic

malphodo

Jul 23, 2012, 10:30 am Last Edit: Jul 23, 2012, 12:11 pm by malphodo Reason: 1
Bonjour à tous, je bloque sur un truc bête :(

Je cherche la présence d'une string dans une autre (message UDP) et bien ca soit basique ca fait planter mon programme qui reboot dés que j'essaye de manipuler les strings.
Au début je pensais que cela venait de caractères spéciaux présents mais je m'aperçois que non et qu'en sortant la ligne de commande d'une condition donnée ca marche  :~

Ci dessous mon code modifié avec un exemple (j'ai fait un copier/coller de ce bout de code test sur les string) :

                               
Code: [Select]
//test string
                                String stringOne = "/1/push1/z";
                                int firstClosingBracket = stringOne.indexOf("push1");
                                Serial.println("The index of > in the string " + stringOne + " is " + firstClosingBracket);
                              //fin de test


Quand il est dans dans la condition :
Code: [Select]
if (buf[IP_PROTO_P]==IP_PROTO_UDP_V){
}


ca fait planter mon code, par contre si je le sors de la condition ca passe très bien !?

Help .... je suis à court d'idée là  =(

Le code avec le commentaire :
Code: [Select]

#include "EtherShield.h"

uint8_t mymac[6] = {0x54,0x55,0x58,0x10,0x00,0x25};
uint8_t myip[4] = {192,168,1,25};
uint16_t MYWWWPORT = 80;
uint16_t outgoingport = 12345;

#define BUFFER_SIZE 750
static uint8_t buf[BUFFER_SIZE+1];

char reply[]="00000000";
String UDPMsg;
char c;
EtherShield es=EtherShield();

uint16_t plen, dat_p;
static uint8_t udp_length;
static uint8_t udp_buffer[50];

///----------------------------------------------------------
void setup(){
 
 Serial.begin(9600);
 Setup_Pins();
 es.ES_enc28j60Init(mymac);
 es.ES_init_ip_arp_udp_tcp(mymac,myip, MYWWWPORT);
 Serial.println("Start");
} // end setup
///----------------------------------------------------------
void loop(){
 
             // read packet, handle ping and wait for a tcp packet:
             dat_p=es.ES_packetloop_icmp_tcp(buf,es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf));
             
             if (buf[IP_PROTO_P]==IP_PROTO_UDP_V){
                //Serial.println(buf[IP_PROTO_P]);
               
               
                              udp_length=buf[39]-16; // calculate UDP data lenght
                            // udp_length=buf[39]-8; // calculate UDP data lenght
                             
                              for (int i = 0; i < udp_length; i++)
                              {
                                    //Serial.write(buf[42+i]);
                                     c = buf[42+i];
                                     UDPMsg += c;
                              }//end for
                             
                              Serial.println(UDPMsg);
                               
                                                             
                              //test string -> ca fait planter mon code
                                String stringOne = "/1/push1/z";
                                int firstClosingBracket = stringOne.indexOf("push1");
                                Serial.println("The index of > in the string " + stringOne + " is " + firstClosingBracket);
                              //fin de test
                             
                              //Relay_Control();
                              //Status_Reply();
                              //es.ES_make_udp_reply_from_request(buf,reply,8,outgoingport);
                              buf[IP_PROTO_P]=0;
                              UDPMsg="";
             } //end if
 //test string -> ca marche
 String stringOne = "/1/push1/z";
 int firstClosingBracket = stringOne.indexOf("push1");
 Serial.println("The index of > in the string " + stringOne + " is " + firstClosingBracket);
 //fin de test
 
} // end loop

skizoh

bonjour, si tu met autre chose dans ce if sa passe? genre un delay un serial.print ou coi ca passe? moi je pense que c'est dans tes condition que une variable doit déconné :s

fdufnews

Quel micro sur ta carte? car tu utilises pas mal de RAM déjà et donc lors de la création de stringOne peut être as-tu un débordement.

skywodd

Bonjour,


Quel micro sur ta carte? car tu utilises pas mal de RAM déjà et donc lors de la création de stringOne peut être as-tu un débordement.

+1 l'hypothèse du débordement semble la plus probable.

Une bonne façon de savoir si c'est ça :
http://arduino.cc/playground/Code/AvailableMemory
Des news, des tutos et plein de bonnes choses sur http://skyduino.wordpress.com !

malphodo

Merci pour vos réponses.

C est une carte chinoise avec 4 relais et le Shields ethernet intègr?.
Les caractéristiques :

• Flash Memory 32 KB (ATmega328) of which 2 KB used by bootloader
• SRAM 2 KB (ATmega328)
• EEPROM1 KB (ATmega328)
• Clock Speed 16 MHz

Je fais un test des demain avec une fonction de test mémoire et vous tiens au courant.!

skizoh

teste autre chose dans ce if déjà pour en avoir le coeur net c'est simple et ça mettra une partie hors de cause !

malphodo

Bon je deterre mon post car je reprend mon petit projet et j'ai tjs mon probleme :)

j'ai testé des println et ca passe, et j'ai donc testé une mesure de ram.

Voici la derniere version du code en 3 parties :

le main :

Code: [Select]
#include "EtherShield.h"

uint8_t mymac[6] = {0x54,0x55,0x58,0x10,0x00,0x25};
uint8_t myip[4] = {192,168,1,25};
uint16_t MYWWWPORT = 80;
uint16_t outgoingport = 12345;

#define BUFFER_SIZE 750


static uint8_t buf[BUFFER_SIZE+1];
int thisByte = 33;
char reply[]="/1/label1 ok";
String UDPMsg;
char c;
EtherShield es=EtherShield();

uint16_t plen, dat_p;
//static uint8_t udp_length;
//static uint8_t udp_buffer[50];
uint8_t udp_length;
uint8_t udp_buffer[50];

///----------------------------------------------------------
void setup(){
 
  Serial.begin(9600);
  Setup_Pins();
  es.ES_enc28j60Init(mymac);
  es.ES_init_ip_arp_udp_tcp(mymac,myip, MYWWWPORT);
  //Serial.println();
  Serial.println("Start");
  Serial.println(freeRam());

} // end setup
///----------------------------------------------------------
void loop(){
             
              // read packet, handle ping and wait for a tcp packet:
              dat_p=es.ES_packetloop_icmp_tcp(buf,es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf));
         
              if (buf[IP_PROTO_P]==IP_PROTO_UDP_V){
               
                               udp_length=buf[39]-16; // calculate UDP data lenght
                             
                               for (int i = 0; i < udp_length; i++)
                               {
                                     //Serial.write(buf[42+i]);
                                      c = buf[42+i];
                                      UDPMsg += c;
                               }//end for
               delay(500);
               Serial.println(UDPMsg.indexOf("push1/z"));
               delay(500);
                                     
   
                               buf[IP_PROTO_P]=0;
                               UDPMsg="";
              } //end if

 
} // end loopThe ram test function :


la page de fonction reduite pour le moment a la mesure de la memoire :

Code: [Select]
///----------------------------------------------------------

int freeRam () {
  extern int __heap_start, *__brkval;
  int v;
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}

///----------------------------------------------------------



et pour finir un petite page de config des sorties :

Code: [Select]
///----------------------------------------------------------
void Setup_Pins(){
 
  pinMode(5, OUTPUT); digitalWrite(5, 0);
  pinMode(6, OUTPUT); digitalWrite(6, 0);
  pinMode(7, OUTPUT); digitalWrite(7, 0);
  pinMode(8, OUTPUT); digitalWrite(8, 0);
 
} // end Setup_Pins




Quand je lance tout çà :

sans envoyer de trame :
j'obtiens sur le port serie :

Start
993
Start
993
Start
993
Start
993

les reboot arrivent generalement toutes les 2-3 minutes
le test de mémoire retourne "993" je ne vois pas ce que ca peut representer ! c est suffisant ? à noter que j'ai aussi un test en baissant la taille du buffer (
#define BUFFER_SIZE xxx)  et j'avait en resultat 1200 environ et ca continuait à rebooter...

Ensuite quand j'envois des trames OSC :

Start
993
3
Start
993
-1
Start
993
Start
993

Là on voit que à part les reboot ca marche j'obtiens "3" à la premiere trame qui correspond à la position du caractere recherché et -1 au deuxieme car la trame ne contenait pas ce que je cherche par contre ca reboot immédiatement apres le resultat, apres ca continu a rebooter toutes les 2-3 minutes.


Etant à court d'idée j'ai aussi posé la question à l'editeur de la carte on verra bien ....

Question bete liée au fait que je comprend pas encore tout le code :

Code: [Select]
void loop(){
 
              // read packet, handle ping and wait for a tcp packet:
              dat_p=es.ES_packetloop_icmp_tcp(buf,es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf));


J'ai du mal à visualiser le fonctionnement imbriqué du loop et de l'evenement de lecture du buffer, ya pas de risque que le contenu de dat_p change plus vite que le traintement complet de mon loop (pas facile à decrire l'idée là  :D)

Merci de votre aide !

fdufnews

Code: [Select]
for (int i = 0; i < udp_length; i++)
                               {
                                     //Serial.write(buf[42+i]);
                                      c = buf[42+i];
                                      UDPMsg += c;
                               }//end fo


Je me demande si cette partie ne pourrait pas te jouer un mauvais tour.
Ta mesure de la mémoire disponible est réalisée à la fin du setup(). Toutes les variables sont créées à leur taille finale sauf UDPMsg la chaîne n'est pas initialisée donc sa longueur est nulle.
Lorsque tu la construis en ajoutant un caractère il est possible que quelque fois elle grossisse trop et bouffe le stack.

Pour vérifier ça, tu pourrais créer une variable longueur que tu mettes à zéro à l'initialisation et quand tu réinitialises la chaîne
Code: [Select]
buf[IP_PROTO_P]=0;
UDPMsg="";
longueur = 0;

Et tu l'incrémenterais lorsque tu ajoutes un caractère à la chaine
Code: [Select]
for (int i = 0; i < udp_length; i++)
                               {
                                     //Serial.write(buf[42+i]);
                                      c = buf[42+i];
                                      UDPMsg += c;
                                      longueur++;
                               }//end fo

Il faudrait l'envoyer par la console pour voir si elle ne devient pas plus grande que la place libre en mémoire. Sans perdre de vue qu'il y a en plus des variables locales créées dans les fonctions appelées dans la librairie Ethershield.

malphodo

#8
Sep 28, 2012, 07:28 am Last Edit: Sep 28, 2012, 08:03 am by malphodo Reason: 1
hello merci de t'intéresser à mon sujet  ;)

Ce que tu propose de serveiller je peux aussi le recupérer dans "udp_length" logiquement ?

Je vais de ce pas faire quelques tests pour vérifier :)

Edit :

Donc voilà les resultats :

Le code modifié avec quelques traçages supplémentaires de la RAM, en mettant quelques commentaires et en ajoutant quelques delay :

Code: [Select]
#include "EtherShield.h"

uint8_t mymac[6] = {0x54,0x55,0x58,0x10,0x00,0x25};
uint8_t myip[4] = {192,168,1,25};
uint16_t MYWWWPORT = 80;
uint16_t outgoingport = 12345;

#define BUFFER_SIZE 750


static uint8_t buf[BUFFER_SIZE+1];
int thisByte = 33;
char reply[]="/1/label1 ok";
String UDPMsg;
char c;
EtherShield es=EtherShield();

uint16_t plen, dat_p;
uint8_t udp_length;
uint8_t udp_buffer[50];

///----------------------------------------------------------
void setup(){
 
  Serial.begin(9600);
  Setup_Pins();
  es.ES_enc28j60Init(mymac);
  es.ES_init_ip_arp_udp_tcp(mymac,myip, MYWWWPORT);
 
  Serial.println(" ");
  Serial.print("Start RAM ");
  Serial.println(freeRam() );
   
} // end setup
///----------------------------------------------------------
void loop(){
             
              // read packet, handle ping and wait for a tcp packet:
              dat_p=es.ES_packetloop_icmp_tcp(buf,es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf));
         
              if (buf[IP_PROTO_P]==IP_PROTO_UDP_V){
               
                               udp_length=buf[39]-18; // calculate UDP data lenght
                               Serial.print("udp_length ");
                               Serial.println(udp_length);
                               Serial.print("RAM ");
                               Serial.println(freeRam());
                               
                               for (int i = 0; i < udp_length; i++)
                               {
                                     //Serial.write(buf[42+i]);
                                      c = buf[42+i];
                                      UDPMsg += c;
                                      delay(10);
                               }//end for
               Serial.print("RAM aprés traitement ");
               Serial.println(freeRam());               
               delay(100);
               Serial.println(UDPMsg);
               Serial.println(UDPMsg.indexOf("push1/z"));
               delay(100);
                                     
   
                               buf[IP_PROTO_P]=0;
                               UDPMsg="";
              } //end if

 
} // end loop


Resultat :


Quote
Start RAM 945

Start RAM 945

Start RAM 945

Start RAM 945

Start RAM 945
udp_length 10
RAM 700
RAM aprés traitement 691
/1/push1/z
3

Start RAM 945


On constate encore 4 plantages à sans trame UDP (environ 1 plantage à la minute)  :smiley-roll:
Et visiblement pas de débordement de la RAM et UDP_Lenght qui est de 10 caracteres


Maintenant le meme code avec suppression des delay :

Quote
Start RAM 945

Start RAM 945

Start RAM 945

Start RAM 945

Start RAM 945

Start RAM 945


Plantage à vide au depart, et ensuite plantage complet avec retour de caractères incohérents à l'envoi de trames....  :smiley-sad-blue:



malphodo

Alors quand même précision importante sur la trame utilisée :

Exemple de trame UDP quand j'appuie sur le bouton 1 de mon emeteur (touchOSC iphone)

Quote
/1/push1/z
/1/push1
/1/push1
/1/push1/z


Les deux premières lignes sont envoyées lorsque qu'on appuie sur le bouton, les deux dernières quand on relache, ca fait donc 4 trames à la suite, constant que je ne trappais qu'une ligne à chaque fois sur la console, j'ai augmenté la vitesse du port serie à 115200 bauds.

Nouveau test de code en laissant tout sauf la commande de manip string :

Code: [Select]

#include "EtherShield.h"

uint8_t mymac[6] = {0x54,0x55,0x58,0x10,0x00,0x25};
uint8_t myip[4] = {192,168,1,25};
uint16_t MYWWWPORT = 80;
uint16_t outgoingport = 12345;

#define BUFFER_SIZE 750


static uint8_t buf[BUFFER_SIZE+1];
int thisByte = 33;
char reply[]="/1/label1 ok";
String UDPMsg;
char c;
EtherShield es=EtherShield();

uint16_t plen, dat_p;
uint8_t udp_length;
uint8_t udp_buffer[50];

///----------------------------------------------------------
void setup(){
 
  Serial.begin(115200);
  Setup_Pins();
  es.ES_enc28j60Init(mymac);
  es.ES_init_ip_arp_udp_tcp(mymac,myip, MYWWWPORT);
 
  Serial.println(" ");
  Serial.print("Start RAM ");
  Serial.println(freeRam() );
   
} // end setup
///----------------------------------------------------------
void loop(){
             
              // read packet, handle ping and wait for a tcp packet:
              dat_p=es.ES_packetloop_icmp_tcp(buf,es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf));
         
              if (buf[IP_PROTO_P]==IP_PROTO_UDP_V){
                               
                               udp_length=buf[39]-18; // calculate UDP data lenght
                               Serial.print("udp_length ");
                              Serial.println(udp_length);
                               Serial.print("RAM ");
                               Serial.println(freeRam());
                               
                               for (int i = 0; i < udp_length; i++)
                               {
                                     //Serial.write(buf[42+i]);
                                      c = buf[42+i];
                                      UDPMsg += c;                                     
                               }//end for
               Serial.print("RAM aprés traitement ");
               Serial.println(freeRam());               

              Serial.println(UDPMsg);
//              Serial.println(UDPMsg.indexOf("push1/z")); -> **************manip string en commentaire ***************

//                                     
//   
                               buf[IP_PROTO_P]=0;
                               UDPMsg="";
              } //end if

 
} // end loop


Résultat :

Quote
Start RAM 953
udp_length 10
RAM 708
RAM aprés traitement 699
/1/push1/z
udp_length 10
RAM 699
RAM aprés traitement 699
/1/push1##
udp_length 10
RAM 699
RAM aprés traitement 699
/1/push1##
udp_length 10
RAM 699
RAM aprés traitement 699
/1/push1/z



On constate :

-Pas de plantage sans trame UDP
-les 4 trames sont bien trappées

Je ne comprend meme pas pourquoi ca plante à vide, c'est pas un probleme de memoire et l'evenement n'est pas censé se produire sans trame UDP =(

malphodo

#10
Sep 28, 2012, 09:59 am Last Edit: Sep 28, 2012, 11:11 am by malphodo Reason: 1
On continu sur le meme theme  :smiley-roll:

Tests intéressant :

Test 1 :

Je sors le test de string de la boucle "evenement udp"  en passant le contenu de UDPMSG dans uns string UDPMSG2


Code: [Select]
void loop(){
             
patati patata de code que je ne remet pas
                       
              Serial.println(UDPMsg);
//              Serial.println(UDPMsg.indexOf("push1/z"));
                              buf[IP_PROTO_P]=0;
                              UDPMsg2 =UDPMsg;                              
                              UDPMsg="";
             } //end if
           
if (UDPMsg2 != ""){
 Serial.println(UDPMsg2.indexOf("push1/z"));
  UDPMsg2="";
} //end if
} // end loop


Le résultat est le même plantage sur le indexof


Test 2 :


Code: [Select]
//              Serial.println(UDPMsg.indexOf("push1/z"));
                              buf[IP_PROTO_P]=0;                            
                              UDPMsg="";
             } //end if
UDPMsg2 = "/1/test/push1/z";            
if (UDPMsg2 != ""){
 Serial.println(UDPMsg2.indexOf("push1/z"));
  UDPMsg2="";
} //end if
} // end loop


là le résultat est intéressant :

Quote
8
8
8
8
8
8
8
8
8
8
ud°
Start RAM 918
8
8


On constate que le test indexof fonctionne bien et ne fait pas planter le code, sauf quand j'envois une trame UDP en plus, qui pourtant n'est pas traitée par la cherche de caractère ...

Ca serait peut etre un problème de format de variables ? mais le comportement ressemble plus à un problème de boucle ou d'événement imbriqués ayant des vitesse d''exécution différentes ...

Exemple le temps que l'indexof aboutisse le contenu de UDPMSG a deja changé ... a votre avis ?

malphodo

A force de creuser ....

J'ai externalisé la fonction d'analyse de string :

Le code :

Code: [Select]
void loop(){
             
              // read packet, handle ping and wait for a tcp packet:
              dat_p=es.ES_packetloop_icmp_tcp(buf,es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf));
         
              if (buf[IP_PROTO_P]==IP_PROTO_UDP_V){
                                                           
                               udp_length=buf[39]-18; // calculate UDP data lenght
                             
                               for (int i = 0; i < udp_length; i++)
                               {
                                     //Serial.write(buf[42+i]);
                                      c = buf[42+i];
                                      UDPMsg += c;                                     
                               }//end for

                 search();
                 buf[IP_PROTO_P]=0;

              } //end if
         

} // end loop



et la fonction :

Quote
void search(){

  if (UDPMsg != ""){
                              if (UDPMsg.indexOf("push1/z") > 1 )
                                {
                                  Serial.println("Bouton1");
                                  flag1 = flag1 + 1;
                                      if (flag1 == 2 )
                                        {
                                            digitalWrite(5, 1);
                                            delay(2000);
                                            digitalWrite(5, 0);
                                            flag1 = 0;
                                         }
                                }
                              else if (UDPMsg.indexOf("push2/z") > 1 )
                                {
                                  Serial.println("Bouton2");
                                  flag2 = flag2 + 1;
                                      if (flag2 == 2 )
                                        {
                                  digitalWrite(6, 1);
                                  delay(2000);
                                  digitalWrite(6, 0);
                                  flag2 = 0;
                                         }
                                                                   
                                } //end if
                               
                               
                     UDPMsg="";
                    } //end if

} // end Search


et là ca fonctionne  :D

Go Up