[risolto] AT e buffer seriale

ciao ragazzi,
ho un problema, ed oltre a questo, ho anche il problema di riuscire a descriverlo :fearful:
ci provo:
ho uno sketch che pilota un cellulare in seriale tramite comandi AT. il suo compito è quello di leggere degli sms ed estrapolare dei valori. inviando un sms ad arduino preceduto da # do dei comandi da eseguire. devo anche poter leggere i messaggi inviati da vodafone con il credito residuo.
questo è ciò che ho scritto:

String inputString = "";         // a string to hold incoming data
boolean stringComplete = false;  // whether the string is complete

void setup()  {
  Serial.begin(9600);
  Serial1.begin(9600); 

  Serial1.println("AT");                          // sveglia device
  delay(80);
  Serial1.println("AT+CMGF=1");                    //imposta sms in modalita testo
  delay(80);
  Serial1.println("AT+CMGR=2");                    //legge messaggio

}

void loop() {
  readSms();
}

void readSms() {
  while (Serial1.available()) {
    char inChar = (char)Serial1.read();                               // get the new byte:
    inputString += inChar;                                            // add it to the inputString:
//Serial.println(inputString);
    if (inChar == '\n') {                                             // if the incoming character is a newline, set a flag
      stringComplete = true;

      if ( inputString.startsWith("Il tuo credito", 0) ){
        String credito = inputString.substring( 55, 60);
        Serial.print(F("Credito residuo: "));
        Serial.println ( credito );
      }

      if ( inputString.startsWith("#", 0) ){
        String comando = inputString.substring( 1, 10);
        Serial.print(F("Comando SMS ricevuto: "));
        Serial.print ( comando );
      }
    } 
  }

  if (stringComplete) {                                                 // print the string when a newline arrives:
    // Serial.println(inputString); 
    inputString = "";                                                   // clear the string:
    stringComplete = false;
  }
}

il codice funziona, ma a volte si presentano problemi strani.
ad esempio, se sposto i comandi AT all'interno di readSms(), non va pi√Ļ, ma se resetto arduino pi√Ļ di una volta pu√≤ capitare che una volta su mille dia il risultato giusto.
la stessa cosa capita se provo a decommentare una delle righe di debug.
idem se inserisco un delay nel loop().
credo che il problema sia legato alla scrittura/lettura del buffer, ma non riesco a trovare una soluzione.
capisco che non sarà facile rispondere, perchè mi rendo conto di non aver spiegato al meglio il problema e non tutti avranno il materiale per fare delle prove, per cui se posso postare qualcosa che aiuti a capire ditemi pure.
grazie

Che scheda stai usando?
Visto che leggo Serial1 non è una UNO. Oppure non hai messo l'inizializzazione della serialsoftware.

sto usando la MEGA 2560.

E se dividi le funzioni?

String inputString = "";         // a string to hold incoming data
boolean stringComplete = false;  // whether the string is complete

void setup()  {
  Serial.begin(9600);
  Serial1.begin(9600); 

  Serial1.println("AT");                          // sveglia device
  delay(80);
  Serial1.println("AT+CMGF=1");                    //imposta sms in modalita testo
  delay(80);
  Serial1.println("AT+CMGR=2");                    //legge messaggio
}

void loop() {
  readSms();
  if (stringComplete) checkSms();
}

void checkSms() {
  if ( inputString.startsWith("Il tuo credito", 0) ){
    String credito = inputString.substring( 55, 60);
    Serial.print(F("Credito residuo: "));
    Serial.println ( credito );
  }

  if ( inputString.startsWith("#", 0) ){
    String comando = inputString.substring( 1, 10);
    Serial.print(F("Comando SMS ricevuto: "));
    Serial.print ( comando );
  }

  inputString = "";                                                   // clear the string:
  stringComplete = false;
}


void readSms() {
  while (Serial1.available()) {
    char inChar = Serial1.read();                               // get the new byte:
    inputString += inChar;                                            // add it to the inputString:
    //Serial.println(inputString);
    if (inChar == '\n') stringComplete = true;
  } 
}

grazie Paolo, ho provato ma il risultato è il medesimo.
è una settimana che ci sto sopra, ho provato mille modi di riscrivere il codice....
quello che pi√Ļ mi preme √® di togliere i comandi AT dal setup() e inserirli nella funzione, o al limte in una funzione a parte, perch√® poi mi servir√† all'interno di un altro progetto.

Crea una funzione initSms() e metti dentro l'inizializzazione e la chiami dal setup.
Controlla semmai cosa deve restituire la periferica quando riceve qui comandi.

in grassetto i comandi:

AT
OK
AT+CMGF=1
OK
AT+CMGR=2
+CMGR: "REC READ","404","Tra","13/09/28,22:54:00+08",161,0,0,0,"39404",145,156
Il tuo credito disponibile al 28-09-2013 alle 22:54 e' 15.15 euro.Ultimo addebito 0.30 euro.Per tenere sotto controllo il traffico registrat....

OK

AT+CMGR=1
+CMGR: "REC READ","39347XXXXXXX","_CG8V@@1","13/09/28,22:33:12+08",145,4,0,0,"393492000200",145,6
#start

OK

Crea una funzione initSms() e metti dentro l'inizializzazione e la chiami dal setup.

questo non posso farlo, perchè dal setup quei comandi verrebbero eseguiti una sola volta all'avvio di arduino, mentre mi servirebbe poterlo fare in qualsiasi momento.

Ogni volta che invii un comando devi leggere da seriale la risposta e poi cancellare eventuali altri contenuti.

ho semplificato un po' le cose, ma il risultato sfugge alla mia comprensione....

String inputString = "";         // a string to hold incoming data
char inChar ;
int i=0;

void setup()  {
  Serial.begin(9600);
  Serial1.begin(9600); 
}

void loop() {

  //primo comando
  Serial1.print("AT\r");                          // sveglia device
  delay(200);
  Serial.print ( readSerial() );

  Serial.print ( "----------- loop: " );  Serial.println ( i++ );

}

String readSerial() {
  while (Serial1.available()) {
    inChar = Serial1.read();                     // get the new byte:
    inputString += inChar;                                  // add it to the inputString:
    String serialReply = "";
    if (inChar == '\n') {                                   // if the incoming character is a newline, set a flag
      serialReply = inputString;
      inputString = ""; 
      return (serialReply) ;
    } 
  }
}

sul monitor ottengo:

AT
----------- loop: 0
OK
----------- loop: 1
AT
----------- loop: 2
OK
----------- loop: 3
AT
----------- loop: 4
OK
----------- loop: 5
AT
----------- loop: 6
OK
----------- loop: 7
AT
----------- loop: 8
OK
----------- loop: 9
AT
----------- loop: 10
OK
----------- loop: 11
AT
----------- loop: 12
OK
----------- loop: 13
AT
----------- loop: 14
OK
----------- loop: 15
AT
----------- loop: 16
OK
----------- loop: 17
AT
----------- loop: 18
OK
----------- loop: 19
AT
----------- loop: 20
OK
----------- loop: 21
AT
----------- loop: 22
OK
----------- loop: 23
AT
----------- loop: 24
OK
----------- loop: 25
AT
----------- loop: 26
OK
----------- loop: 27
AT
----------- loop: 28
OKAT
----------- loop: 29
AT
----------- loop: 30
AT
----------- loop: 31
AT
----------- loop: 32
AT
----------- loop: 33
AT
----------- loop: 34
AT
----------- loop: 35
AT
----------- loop: 36
AT
----------- loop: 37
AT
----------- loop: 38
AT
----------- loop: 39
AT
----------- loop: 40
AT
----------- loop: 41
AT
----------- loop: 42
AT
----------- loop: 43
AT
----------- loop: 44
OKAT
----------- loop: 45
AT
----------- loop: 46
AT
----------- loop: 47
AT
----------- loop: 48
AT
----------- loop: 49
AT
----------- loop: 50
AT
----------- loop: 51
AT
----------- loop: 52
AT
----------- loop: 53
AT
----------- loop: 54
AT
----------- loop: 55
AT
----------- loop: 56
AT
----------- loop: 57
AT
----------- loop: 58
AT
----------- loop: 59
AT
----------- loop: 60
OKAT
----------- loop: 61
AT
----------- loop: 62

dal loop 30 in poi inizia ad andare in tilt. cosa ne dovrei dedurre? il buffer è pieno (intorno ai 64byte dovremmo esserci)? ma in teoria la funzione readSerial() dovrebbe leggere e cancellare di conseguenza giusto?
poi, perchè al primo loop mi stampa il comando e al loop successivo la risposta?

Nella funzione che chiami la prima istruzione è un while.
Tu gli dici: mentre ci sono dei dati nella seriale, fai questo..

Ma se i dati nel buffer di ricezione della seriale ancora non ci sono, lui esce. E quindi torna al loop dove ti stampa ".........loop xx".

leo72:
Nella funzione che chiami la prima istruzione è un while.
Tu gli dici: mentre ci sono dei dati nella seriale, fai questo..

Ma se i dati nel buffer di ricezione della seriale ancora non ci sono, lui esce. E quindi torna al loop dove ti stampa ".........loop xx".

in teoria la tua risposta ha un senso, ma nella pratica non trovo riscontro.
ho provato con un abbondante delay dentro il while e dopo l'invio del comando AT ma non cambia nulla. o forse non ho capito il tuo suggerimento?
c'è da dire che provando il telefono con minicom la risposta è pressochè istantanea.
altra cosa che non capisco è perchè il comando che invio finisce nel buffer... è normale? c'è un buffer anche in trasmissione?

Sull’Arduino ci sono 2 buffer seriali, uno RX ed un TX. Qualunque cosa spedita verso o ricevuta dalla seriale finisce prima in uno di quei due buffer.

credo di essere giunto ad una soluzione utilizzando il serialEvent().
e dire che avevo guardato pi√Ļ volte quell'esempio, per non dire che l'avevo utilizzato come base di partenza (cambiando il nome alla funzione :stuck_out_tongue_closed_eyes:) senza averne capito il significato :sweat_smile: e nel reference mi era proprio sfuggito.

/*
** SerialEvent occurs whenever a new data comes in the**
hardware serial RX. This routine is run between each
time loop() runs, so using delay inside loop can delay
response. Multiple bytes of data may be available.
*/

scusate e grazie a tutti per la pazienza :slight_smile:

PS: una cosa non ho capito in quell'esempio:

void setup() {
inputString.reserve(200);
}

:roll_eyes: ??

E' un metodo non documentato dell'oggetto String.
In pratica, alloca dinamicamente nello stack un blocco di RAM pari al dato che gli passi, in modo da evitare overflow dello stack stesso, che con l'oggetto String sono molto facili dato che la RAM del chip è limitata.