SoftwareSerial, again... (missing characters)

Hello all!

I am currently working on a project that needs to send and receive SMS. For this, I use a SIM800L module, which communicates through serial. As I need to make my final project as little as possible, I have decided to work on a nano.

So in the end, I need to use the SoftwareSerial library.

When I use my arduino as a serial relay, I have no problem. Everything works fine. I use this to test the commands before writing them in the final code.
Here is the code:

#include <SoftwareSerial.h>

SoftwareSerial gsm(7,8);

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

}

void loop() {
  if(Serial.available()) gsm.print(Serial.readString());
  if(gsm.available()){
    String temp=gsm.readString();
    Serial.print(temp);
    for(int i=0; i<temp.length(); i++){
      Serial.print(temp[i],DEC);
      Serial.print(" ");
    }
    Serial.println();
  }

}

As my code is pretty long, I have decided to write a library (by the way, I couldn't find an existing library working for me...). I successfully send SMS but when it comes to receive them, I have issues. Some characters are lost. I tried to extend the buffer size but same result... I really put all my knowledge on this, I really can't fix this.
Moreover, it happens that the arduino stops running, it looks like it is in an infinite loop but I haven't find where.
Has anyone a solution for me?

Here are the files (.h and .cpp) I'm writing. They are messy but understand this is a work in progress.

.h file:

//GSM_Balise.h
#include <Arduino.h>
#include <SoftwareSerial.h>

#ifndef GSM_Balise_h
#define GSM_Balise_h

class GSM_Balise:public SoftwareSerial{
private:
 //String pinCode="8076";
 unsigned long _startMillis;
 unsigned long _timeout=1000;

public:
 
 GSM_Balise(uint8_t rx=7, uint8_t tx=8);
 
 int GSMTimedRead();
 String GSMReadString();
 
 void update();
 void unlock(String _pinCode="8076");
 void toTextMode();
 void sendSMS(String _text, String _num="+32xxxxxxxxx");
 void SMS();
 void reset();
 
 
 uint8_t resetPin=6;
 bool unlocked=false;
 bool SMSOk=false;
 bool callOk=false;
 bool textMode=false;
 bool flagSendSMS=false;
 bool texting=false;
 bool waitSMSSending=false;
 bool SMSWritten=false;
 bool SMSAvailable=false;
 
 
 char rawData;
 String text;
 String num;
 String data[10];
};

#endif

.cpp file:

#include <GSM_Balise.h>

GSM_Balise::GSM_Balise(uint8_t rx, uint8_t tx)
 : SoftwareSerial(rx, tx){
 
 SoftwareSerial::begin(9600);
 
 pinMode(resetPin,OUTPUT);
 digitalWrite(resetPin,HIGH);
}

int GSM_Balise::GSMTimedRead(){
  int c;
  _startMillis = millis();
  do {
    c = read();
    Serial.print(c); Serial.print(' ');
    if (c >= 0) return c;
  } while(millis() - _startMillis < _timeout);
  return -1;     // -1 indicates timeout
}

String GSM_Balise::GSMReadString()
{
  String ret;
  int c = GSMTimedRead();
  while (c >= 0)
  {
     if(c==10) return ret;
     if(c!=10 && c!=13) ret += (char)c;
     c = GSMTimedRead();
  }
  return ret;
}

void GSM_Balise::update(){
 
  if(flagSendSMS) SMS();
 
  //if(available()) Serial.print(readString());
 
  if(available()){
 
    String temp=GSMReadString();
    if(temp!=" " && temp!=""){
      for(int i=10; i>0; i--){
        data[i]=data[i-1];
      }
      data[0]=temp;
    }
    /*for(int i=0; i<10; i++){
    Serial.print(" message "); Serial.print(i); Serial.print(" : ");Serial.print(data[i]);
  }
  Serial.println();*/
 
  /*do{
    rawData=read();
    if(rawData!='\r'&& rawData!='\n') data[0]=data[0]+rawData;
    delay(5);
  }while(rawData != '\n' && available());
 
 
  delay(50);
  Serial.println(data[0]);
  for(int i=0; i<data[0].length(); i++){
    Serial.print(data[0][i],DEC);
    Serial.print(" ");
  }
  Serial.print('\n');*/
 
  if(data[0]=="+CPIN: READY") {unlocked=true;}
  else if(data[0]=="Call Ready") {callOk=true;}
  else if(data[0]=="SMS Ready") {SMSOk=true;waitSMSSending=false;}
  else if(data[0]=="OK" && data[1]=="AT+CMGF=1") {textMode=true;waitSMSSending=false;}
  else if(data[0]=="AT+CMGS=\""+num+"\"") {texting=true;waitSMSSending=false;}
  else if(data[0]==("> " + text)) {SMSWritten=true;waitSMSSending=false;}
 
 
  if(available()==0){
    for(int i=0; i<10; i++){
      Serial.print(" message "); Serial.print(i); Serial.print(" : ");Serial.print(data[i]);
    }
    Serial.println();
  }
  }
  //delay(1000);
 
}

void GSM_Balise::unlock(String _pinCode){
  println("AT+CPIN=\""+_pinCode+"\"");
}

void GSM_Balise::toTextMode(){
  println("AT+CMGF=1");
}

void GSM_Balise::sendSMS(String _text, String _num){
  num=_num;
  text=_text;
 
  flagSendSMS=true;
}

void GSM_Balise::SMS(){
  if(!SMSOk && waitSMSSending==false) {unlock(); waitSMSSending=true;}
  if(SMSOk && !textMode && waitSMSSending==false) {toTextMode(); waitSMSSending=true;}
  if(textMode && !texting && waitSMSSending==false){
    println("AT+CMGS=\""+num+"\"");
    texting=true;
    waitSMSSending=true;
  }
  if(texting && !SMSWritten && waitSMSSending==false){
    println(text);
    SMSWritten=true;
    waitSMSSending=true;
  }
  if(SMSWritten && waitSMSSending==false){
    write(26);
    Serial.println("SMS sent");
    flagSendSMS=false;
    delay(200);
    reset();
  }
  delay(100);
}

void GSM_Balise::reset(){
  digitalWrite(resetPin,LOW);
  delay(100);
  digitalWrite(resetPin,HIGH);
  delay(4000);
}

.ino file:

#include <GSM_Balise.h>

GSM_Balise gsm(7,8);

unsigned long temps;

void setup() {
  Serial.begin(9600);
  
  //gsm.reset();
  
  //gsm.unlock();
  //gsm.toTextMode();

  //gsm.sendSMS("ESSAI","+32xxxxxxxxx");
  //Serial.println("send request: " + gsm.text + " to " + gsm.num);
  pinMode(13,OUTPUT);
  digitalWrite(13,HIGH);
  temps=millis();
}

void loop() {
  // put your main code here, to run repeatedly:
  gsm.update();

  //if(gsm.textMode) Serial.println("text mode ok");
  
  if(Serial.available()){
    String temp=Serial.readString();
    gsm.print(temp);
  }
  
  delay(100);
  if(millis()-temps>500){ //used only to verify the arduino is still runing
    temps=millis();
    digitalWrite(13, !digitalRead(13));
  }
  
}

Thank's by advance,

Yann.

PS: sorry for the lack of comments... Really sorry!

To make it easy for people to help you please modify your post and use the code button </>
codeButton.png

so your code looks like this and is easy to copy to a text editor. See How to use the Forum

Your code is too long for me to study quickly without copying to my text editor. The text editor shows line numbers, identifies matching brackets and allows me to search for things like all instances of a particular variable or function.

Also please use the AutoFormat tool to indent your code for easier reading.

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. This can happen after the program has been running perfectly for some time. Just use cstrings - char arrays terminated with '\0' (NULL).

Have a look at the examples in Serial Input Basics - simple reliable ways to receive data. There is also a parse example to illustrate how to extract numbers from the received text.

...R

Thanks for your response! I changed everything I could, hope this is going to be ok now...
It is late here so I will try tu use cstring tomorrow. I actually used some String's as they are also used in Stream.h (which is needed for SoftwareSerial, and therefore needed for my library).

Yann.

Hello!

Here is something new.

I have tried a few things and continued to search on the internet. It seem that the problem comes from the interrupts of the original serial and the SoftwareSerial library. For me it is something like this: one of the ports receives something so its interrupts are "triggered". While the first port stores the characters in its buffer, the second port receives also some data and its interrupts are also "triggered". So while this happens, the first port can't store the data anymore hence the dropped characters.

So my question becomes this one: how can I do to be sure that I will never receive data on both ports at the same time? I tried to put some delays between the between reception from one port and emission to the other port but this didn't work...

I also tried to use the cstrings but nothing changed, so I came back to the usual Strings.

Thank's by advance,

Yann.

Your indenting of your code is non-existent so I find it impossible to read.

It would also help if you provide a description of how the parts are intended to work. I can't help feeling you are over-complicating things.

What size is the message for which parts of it get lost?

Serial.readString(); is a blocking function. That could be getting in the way of other business.

...R

Sorry for the indenting, I thought I corrected it but nope... Hope it's ok now!

For the messages, here is an example. In this case, I ask the module to show me the third message in the memory.
What I want: +CMGR: "REC READ","+32496647108","","19/02/20,16:25:38+04"Troisieme smsOK

What I have: +CMGR: "REC READ","+32496647108","","19/02/20,16:25ieme sms

Moreover, in the dropped characters there are some '\r' and '\n', which are used to separate the the received messages. Like this, I should have the confirmation in data[0] ("OK"), the SMS in data[1] ("Troisieme sms") and the rest of the informations (phone number, date...) in data[2].

This happens only on long messages, and the dropped characters are not always the sames.

Thanks!

ProdYJ:
Moreover, in the dropped characters there are some '\r' and '\n',

That suggests to me that the line you describe as "What I want" is incomplete because it had no \r or \n in it.

Can you post an example of the message as it is sent?

...R

PS ... Have you tried receiving the data with the code in my Tutorial ?

Here is the message as it is send:

+CMGR: "REC READ","+32496647108","","19/02/20,16:25:38+04"
Troisieme sms

OK

But when I read the buffer I ignore the '\r' and '\n', and use the '\n' as an end mark; if I read it, I return the String with all the previous chars (to store it) and create a new String with the following data.
So actually, what I should have is:

data[0]=="OK";
data[1]=="Troisieme sms"
data[2]=="+CMGR: "REC READ","+32496647108","","19/02/20,16:25:38+04""

ProdYJ:
Here is the message as it is send:

And what happened when you tried my code?

...R

As said in the first post, I use a code to test the AT commands (with some readString() instead of read()), which works perfectly.

ProdYJ:
As said in the first post, I use a code to test the AT commands (with some readString() instead of read()), which works perfectly.

Does that translate to mean "I have not tried the code in Serial Input Basics ?

Of course you are under no obligation to do so - but it generally works for me.

...R

I think you don't understand what I'm saying...
No I did not use your code, because I have written a similar one adapted to what I need. This code is the first one I gave in my initial post :wink:

Edit:
I tried to rewrite my code without any readString() (I only used read() this time). The result is the same.
The thing that I really do not understand is: the testing code works but when I use the same code trough the library I'm writing, I have this problem of lost chars...

Okay, my problem is solved!

As I guessed it first, the buffer of the softwareSerial was too short. I tried to extend it but didn't work. The reason is that the library is installed twice on my computer (I obviously didn't know it) and I modified the wrong file.

Hope this could help someone else! :wink: