Blocking code

Hello working with the sim800 module via software serial, i've found that arduino never quitted from this function:

String clearGSMBuff() { while (serialSIM800.available()>0){ byte b=serialSIM800.read(); } }

why? The communication with the module it's ok. The purpose was to clear the buffer before attempting a communication and getting the answer, i.e.

clearGSMBuff(); serialSIM800.write("AT\r\n"); delay(100); String a=serialSIM800.readString();

Note that the application worked well when i'm deleted all the calls to clearGSMBuff()

What are all the possible return values of the function serialSIM800.available()?

Have a look at the examples in Serial Input Basics - simple reliable, non-blocking ways to receive data.

It is not a good idea to use the String (capital S) class on an Arduino as it can cause memory corruption in the small memory on an Arduino. Just use cstrings - char arrays terminated with 0.

...R

Thanks to everyone for the suggestions.
Sorry if I answer only now but I did other tests to understand the problem.
I followed Robin’s suggestion, removing strings, and the problem seemed resolved.

Now the program seems to work correctly: but if the sms is sent out after a short time that arduino is turned on, the sms is sent. Therefore after a few days, when sending an sms, arduino crashes. It would seem to be a memory leak but I can not understand what it can depend on.
I’m also thinking of a serialsoftware bug …

Two words about the operation:

The arduino is controlled by a ir remote controller and the alarm activated by motion detection (PIR), power leak (BAT) or fotovoltaic circuit breaking (FV).

The sequence i do is:

  • turn on
  • “up key” : sms test, ok, the sms is sent
  • ‘#’ key (alarm activation). The arduino emits 10 beep then it passes in the alarm detection mode (ciclo_allarme)

When de PIR detect a motion, the sms is sent (intrusion).
If the intrusion is after few hours, the sms is sent. Is the intrusion is after some days, the arduino crashes, after (o during?) the cicle for in sendSMS: i’ve see the led flashing one o two times, then nothing (or random flashes, as i’ve said).
The problem is only when sending sms: alarm activation/deactivation, test (* key), motion detection works well even after several days.

#include <IRremote.h>
#include <SoftwareSerial.h>

#define autostart false

//analog

#define BAT 7
#define FV 4


// Digital IN

#define PIR 4
#define IR 5

#define SIM800_RX_PIN 7

// Digital OUT

#define BEEP 9

#define LED 13
#define SIM800_TX_PIN 8

// IR

IRrecv irrecv(IR);

decode_results results;

char code[8];
char crai[16];
char crai_ok[]="159";
byte pos=0;

char gsmb[32];

//GSM

SoftwareSerial serialSIM800(SIM800_TX_PIN,SIM800_RX_PIN);

#define smsnum "+3934********"

byte fase=0;

byte t;
float v;

unsigned int count=0;

void setup() {
  pinMode (PIR,INPUT);
  pinMode (IR,INPUT);
  
  pinMode (BEEP,OUTPUT);
  pinMode (LED,OUTPUT);

  delay (100);

  irrecv.enableIRIn();
  serialSIM800.begin(9600);
  
  delay(1000);
  
  clearGSMBuff();
   
  serialSIM800.write("ATE0\r\n");
  delay(100);
  
  t=readGSM(gsmb);
  
  if (t==0) {   
    //No GSM!;
    lamp(0.2,0.2);
    lamp(0.2,0.2);
    lamp(0.2,0.2);
  }
  if (strcmp(gsmb,"\r\nOK\r\n")!=0) //GSM OK;
   {
    lamp(0.2,0.2); 
    lamp(0.2,0.2);
   
  }

  serialSIM800.write("AT+CMGF=1\r\n");  //ascii
  delay(100);
  serialSIM800.write("AT+CFUN=4\r\n");  //RF off

    delay(100);
  
}

void loop() {

 switch (fase) 
 {
  case 0:   // Alarm off
      ciclo();
      break;
  case 1:   // premuto #
      preallarme();
      break;
  case 2:   // allarme inserito
      ciclo_allarme();
      break;
  case 3:   // allarme !
      allarme();
      break;
  case 4:
      break;
 }
}
void ciclo() {
  
 if (digitalRead(PIR)) 
      {
        digitalWrite(LED,HIGH);
        count=0;           
      }
      else {
        digitalWrite(LED,LOW);
      }
  
 if (irrecv.decode(&results)) {
    
      switch (decodeir(results.value)) {
        case '#':
          fase=1;     //Pre allarme
          count=0;
          break;
        case '*':
          testAll();
          break;
        case 'U':
          sendSMS("Prova");
          break;
        default:
          break;
    }
    
  irrecv.resume(); // Receive the next value
 }
  delay(100);
  
  count+=1;
  if (count>=10000) count=10000;
  
  if (autostart) {
    if (count>600*30) {   //circa 30 minuti
      
        count=0; //Pre allarme
        fase=1;
    }
  }
  
  if (v<11.5) lprintln("Batt low: "+String(v));    //650
  
}

void preallarme() {
  
  for (int i=0; i<10;i++) {   
    if (irrecv.decode(&results)) {     
      if (decodeir(results.value)=='*') {
        fase=0;   //Abort
        count=0;
        return;
      }
      irrecv.resume(); // Receive the next value
    }
    delay(100);
    lamp (0.5,1);
  }
 
  lamp (2,0);
  fase=2; //Allarme On
  count=0;
}

void ciclo_allarme() {
  
 if (digitalRead(PIR)) 
      {
        if (count==0) lamp(0.1,0.1);
        count+=5;
       }

     if (count>0) count--;
     if (count>200) {
        fase=3;   //Allarme!
        count=0;
        
        while (!sendSMS("Intrusione !!!")) {}     
     }

  v=analogRead(BAT)/64;
  if (v<9) {
        fase=3;   //Allarme!
        count=0;
      
        while (!sendSMS("Batteria!")) {}     
  }
  v=analogRead(FV)/64;
  if (v<5) {
        fase=3;  //Allarme!
        count=0;
       
        while (!sendSMS("Fotovoltaico!")) {}     
  }

if (irrecv.decode(&results)) {
  if (codiceallarme()) {
   
    lamp (2,0);
    fase=0;     //Allarme Off
    count=0;
    return;
  }
  irrecv.resume();
}
  delay(100);

}




void allarme() {
  
  lamp(0.1,0.1);
  
  if (irrecv.decode(&results)) {
    if (codiceallarme()) {
     
      lamp (2,0);
      fase=0;     //Allarme Off
      count=0;
      return;
    }
  irrecv.resume();
}
  lamp(0.1,0.1);
  count++;
  if (count>600*10) { // dopo 10 min
    fase=1;         // pre allarme
    count=0;
    return;
  }
}

boolean sendSMS(const char* data) {
  boolean rete=false;
  
  serialSIM800.write("AT+CFUN=1\r\n");
  delay(3000);
  //String a=serialSIM800.readString();

  for (int i=0;i<5;i++) {
    lamp (0.2,0.1);
    delay(1500);
    clearGSMBuff();
    serialSIM800.write("AT+CREG?\r\n");
     delay(500);
     readGSM(gsmb);
     //lprintln (gsmb);     // 1=ok
     if (gsmb[11]=='1') {
      rete=true;
      break;
     }
  }

  if (rete) {
    lamp (0.5,0.1);
    serialSIM800.write("AT+CMGS=\"");
    serialSIM800.write(smsnum);
    serialSIM800.write("\"\r\n");
    delay(100);
    serialSIM800.println(data);
    delay(100);
    lamp (0.5,0.1);
  //Send Ctrl+Z / ESC to denote SMS message is complete
    serialSIM800.write((char)26);
    delay(10000);
    
    serialSIM800.write("AT+CFUN=4\r\n");  //RF off
   
    lamp (1,1);     //OK beep 1 sec+pausa 1 sec
    return true;
    
  }
   else {
    clearGSMBuff();
    lamp (0.5,0.1);   //NO RETE 2 beep 0.5 sec
    lamp (0.5,0.1);
    return false;
   }
 
  return true;
}

boolean codiceallarme(){
  
    if ((results.value>0xff0000)&&(results.value<0xfffffe)) {
       
     lamp (0.1,0);
     
    if (decodeir(results.value)=='O') {
        crai[pos]=0;
        if (strcmp(crai,crai_ok)==0) {
          pos=0;
          return true;
        } 
        else {
          pos=0;
        }  
    }
    else {
      
      crai[pos]=decodeir(results.value);
     
      pos++;
      if (pos>=14) pos=14;
    }
   
  }
  
   return false;
}
void lamp(float pausa, float pausa2) 
{
  
    digitalWrite(LED,HIGH);
    digitalWrite(BEEP,HIGH);
    delay(pausa*1000);
    digitalWrite(LED,LOW);
    digitalWrite(BEEP,LOW);
    delay(pausa2*1000);
  
}


boolean testGSM() {
  clearGSMBuff();
  serialSIM800.write("AT\r\n");
  delay(100);
  readGSM(gsmb);
  
  if (strcmp(gsmb,"\r\nOK\r\n")==0) {
    return true;  //GSM Ok
  }
  return false;
}

boolean testBatt(){
  v=analogRead(BAT)/64;
  
  if (v<11.5) return false;
 
  return true; //Batt ok
}

boolean testFV() {
   v=analogRead(FV)/64;
  if (v<5) return false;
    return true;
}

void testAll() {
  lamp (0.5,1);
  if (testBatt()) lamp(0.2,0.2);
  delay(1000);
  if (testFV()) {
    lamp(0.2,0.2);
    lamp(0.2,0.2);
  }
    delay(1000);
  if (testGSM()) {
    lamp(0.2,0.2);
    lamp(0.2,0.2);
    lamp(0.2,0.2);
  }
  delay(1000);
  //if (debug) freeRam();
  lamp (0.5,1);

}
char decodeir(unsigned long c) {
  if (c==0xff02fd) return 'O';
  if (c==0xff42bd) return '*';
  if (c==0xff52ad) return '#';
  
  if (c==0xff6897) return '1';
  if (c==0xff9867) return '2';
  if (c==0xffb04f) return '3';
  if (c==0xff30cf) return '4';
  if (c==0xff18e7) return '5';
  if (c==0xff7a85) return '6';
  if (c==0xff10ef) return '7';
  if (c==0xff38c7) return '8';
  if (c==0xff5aa5) return '9';
  if (c==0xff4ab5) return '0';
  if (c==0xff629d) return 'U';
  //lprintln(c);
  return ' ';
  }

void clearGSMBuff() {
  
  while (serialSIM800.available()>0){
          serialSIM800.read();
          delay(10);
  }
}
byte readGSM(char *string) {
  byte availableBytes = serialSIM800.available();
  int i;
  
  for(i=0; i<availableBytes; i++)
  {
    t=serialSIM800.read();
    if (i<31) string[i] = t;   
  }
  if (i<31) string[i]=0;
  else string[31]=0;
  
  return availableBytes;
}
/*

If that was my problem I would produce a much shorter test program to try to isolate the problem - for example is it caused by the SMS process? Or is it created by some other part of the program.

I am not a fan of the infinite WHILE loop such as you use to call the sms function. For example while (!sendSMS("Intrusione !!!")) {} 

You have no means to know why there might be a problem and so you cannot recover from the problem. I would write code that makes a single call and receives back an indication of the problem (if there is one). Or the problems could be handled within the SMS function and then a failure response would mean a major problem so that subsequent calls to the function would be useless.

...R

Hello Robin.
I don’t know if the problem is caused by others functions or blocks of code, but surely it comes out in the sendSMS function.
Today i’ve tried again the alarm after some day of operation in fase 2 (alarm on)
I’ve entered in the room:
-one beep : if (digitalRead(PIR)) { if (count==0) lamp(0.1,0.1);
OK

  • two shorts beep (for (int i=0;i<5;i++) { lamp (0.2,0.1); (…)
    OK : trying to connect the network

… random led flash …

… and directly into ciclo() (fase=0) without entering in the allarme() phase.
NB the version code was without the two instructions lamp (0.5,0.1) i’ve put today to understand precisely the sending sequence.

Therefore this time-dependent failure is really strange: I repeat that both the test function (sendSMS(“Prova”)) and the motion detection alarm (while (!sendSMS(“Intrusione !!!”)) {} ) works well shortly after connecting arduino but fails after some days.

The infinite loop is a little bit ugly, but it’s for security and i think the problem does not depend on that.

PS The next step will be to try Serial instead of SoftwareSerial

brabudu: I don't know if the problem is caused by others functions or blocks of code, but surely it comes out in the sendSMS function.

Then you need to find out by removing different parts of the code.

The infinite loop is a little bit ugly, but it's for security and i think the problem does not depend on that.

Your guess may be correct, but, again you need to make sure.

And what I was also trying to say is that it is not providing any useful security because you have no idea what is happening.

...R