SIM800L GSM Shield with Arduino

Hi Guys,

I hope this is the right section for this question.

I have a whole project which I want to implement a GSM shield in to.

I have been through all the rigmarole to get it actually powered correctly and working.
It connects fine now thankfully!

So the code I am testing with currently; I stole the majority of because I am a rookie with GSM.
I have done a bit of research so I know what it is all doing though.
Or so i thought…

The current code seems to work fine, however it is returning “-1” repetitively every second.

It will execute everything else and even print the SMS when it is received… but it is always sending -1.
Any ideas?

#include <SoftwareSerial.h>

//Create software serial object to communicate with SIM800L
SoftwareSerial GSMSerial(7, 8); //SIM800L Tx & Rx is connected to Arduino #3 & #2
String userInput = "";

void setup()
{
  //Begin serial communication with Arduino and Arduino IDE (Serial Monitor)
  Serial.begin(9600);
  
  //Begin serial communication with Arduino and SIM800L
  GSMSerial.begin(9600);

  Serial.println("Initializing..."); 
  delay(1000);

  GSMSerial.println("AT"); //Once the handshake test is successful, it will back to OK
  updateSerial();
  
  GSMSerial.println("AT+CMGF=1"); // Configuring TEXT mode
  updateSerial();
  GSMSerial.println("AT+CNMI=1,2,0,0,0"); // Decides how newly arrived SMS messages should be handled
  updateSerial();
}

void loop()
{
  updateSerial();
  
}

void updateSerial()
{
  delay(500);
  while (Serial.available()) 
  {
    GSMSerial.write(Serial.read());//Forward what Serial received to Software Serial Port
  }
  while(GSMSerial.available()) 
  {
    Serial.write(GSMSerial.read());//Forward what Software Serial received to Serial Port
  }
  userInput = (GSMSerial.read());
  Serial.println(userInput);
}

The next task as well, is that I want to save the message (not the number or time stamp) into a string. which I assumed would be fairly simple but so far I have failed.

Thanks in advance you clever clever people.

Spice

It will execute everything else and even print the SMS when it is received... but it is always sending -1.
Any ideas?

userInput = (GSMSerial.read());
  Serial.println(userInput);

GSMSerial.read() is a function with a return value, which is the first byte of incoming serial data available (or -1 if no data is available). You are reading userInput outside of the block which checks for GSMSerial.available(). When there is nothing in the receive buffer to be read it returns the -1

The next task as well, is that I want to save the message (not the number or time stamp) into a string. which I assumed would be fairly simple but so far I have failed.

Show us what you have tried.

You would do well to read Robin2's tutorial on reading and parsing serial messages.
SerialInputBasics

With the modem you are using, the message is fully received before the Arduino is notified, and in this case it is OK to read the incoming message into a char array with .readBytes(). For example

while (GSMSerial.available() > 0) //If there is stuff in the buffer
  {
    char textMessage[100] = {}; //size this buffer for the expected message
    byte numChars = GSMSerial.readBytes(textMessage, 100);//.readBytes returns number read
    textMessage[numChars] = '\0';//null Terminator
    Serial.println(textMessage); // Print the new message
    //textMessage is a null terminated character array and you can use all the c-string functions to parse and process the contents.

Thanks Cattledog. First issue is fixed. Not sure why i couldn't think of while >0 ?!?

I have been testing with your code above which is fab, I am just trying to figure out how to ignore all of the number and date stamp data, and not send that to Serial. I only want to send the actual text message to serial.

Any ideas?

Spice

You will need to make of strstr and strncpy .

I am just trying to figure out how to ignore all of the number and date stamp data, and not send that to Serial. I only want to send the actual text message to serial.

Please explain what you want to do. The modem will receive the complete message and typically you process it to capture the information you want to use. You do not have to print out the entire message.

You can use a technique like in the Robin2 tutorial that uses a boolean variable like newMessage = true

For example if the new message were something like

+CMT: "+447xxxxxxxx","","18/09/21,20:54:59+04" Your house is on fire!

The code would typically use strncmp() check to see the +CMT prefix is present and you know that the modem is sending your terminal a message, and then use the appropriate c-string functions to find and display the information you want.

Most people care about the sending number and possibly the time, but if all you want is the final text, you could use strrchr() to find the last " and then print out the message from that point.

//+CMT: "+447xxxxxxxx","","18/09/21,20:54:59+04" Your house is on fire!
//enter the message from serial monitor for testing
char receivedMsg[100];//size for max message
char textMessage[30];//size appropriately for parsed characters
boolean newMessage = false;
boolean prefixMatch = false;
void setup()
{
  Serial.begin(115200);
  //set ms timeout for Serial.readBytes() if no data
  Serial.setTimeout(100);
}

void loop() {

  while (Serial.available() > 0)
  {
    //readBytes returns number read not zero referenced
    byte numChars = Serial.readBytes(receivedMsg, 100);
    receivedMsg[numChars] = '\0';//null Terminate
    newMessage = true;
  }
  //can define a series of prefix messages for match

  if (strncmp(receivedMsg, "+CMT", 4) == 0 && newMessage == true)
  {
    Serial.println("prefixMatch +CMT");
    prefixMatch = true;
    newMessage = false;
  }
  else if (newMessage == true)
  {
    Serial.println("no prefixMatch");
    newMessage = false;
  }
  if (prefixMatch == true)
  {
    prefixMatch = false;
    char* index;
    //find last " with strrchr()
    index = strrchr(receivedMsg, '"');
    strcpy(textMessage,index+1);//copies from after " pointer to ending null
    Serial.print("Text message = ");
    Serial.println(textMessage);
  }
}

Thanks again Cattledog.

I have used your lower code but im having an issue with the prefixMatch not matching.

I have printed receivedMsg to Serial and it looks identical. But is permanently saying "no prefix match".

void newcode() {
  char receivedMsg[100];//size for max message
char textMessage[5];//size appropriately for parsed characters
boolean newMessage = false;
boolean prefixMatch = false;


  while (GSMSerial.available() > 0)
  {
    //readBytes returns number read not zero referenced
    byte numChars = GSMSerial.readBytes(receivedMsg, 100);
    receivedMsg[numChars] = '\0';//null Terminate
    newMessage = true;
  }
  //can define a series of prefix messages for match
  
  if (strncmp(receivedMsg, "+CMT", 4) == 0 && newMessage == true)
  {
    Serial.println("prefixMatch +CMT");
    prefixMatch = true;
    newMessage = false;
  }
  else if (newMessage == true)
  {
    Serial.println("no prefixMatch");
    Serial.println(receivedMsg);
    newMessage = false;
  }
  if (prefixMatch == true)
  {
    prefixMatch = false;
    char* index;
    //find last " with strrchr()
    index = strrchr(receivedMsg, '"');
    strcpy(textMessage,index+1);//copies from after " pointer to ending null
    Serial.print("Text message = ");
    Serial.println(textMessage);
  }
}

Please post the serial print out of the received message and the exact code you are running. I see a function newcode() but I don't know how it is called.

#include <SoftwareSerial.h>

//Create software serial object to communicate with SIM800L
SoftwareSerial GSMSerial(7, 8); //SIM800L Tx & Rx is connected to Arduino #3 & #2
String userInput = "";

void setup()
{
  //Begin serial communication with Arduino and Arduino IDE (Serial Monitor)
  Serial.begin(9600);
  
  //Begin serial communication with Arduino and SIM800L
  GSMSerial.begin(9600);

  Serial.println("Initializing..."); 
  delay(1000);

  GSMSerial.println("AT"); //Once the handshake test is successful, it will back to OK
  updateSerial();
  
  GSMSerial.println("AT+CMGF=1"); // Configuring TEXT mode
  updateSerial();
  GSMSerial.println("AT+CNMI=1,2,0,0,0"); // Decides how newly arrived SMS messages should be handled
  updateSerial();
}

void loop()
{
  newcode();
}

void updateSerial()
{
  delay(500);
  while (Serial.available()>0) 
  {
    GSMSerial.write(Serial.read());//Forward what Serial received to Software Serial Port
  }
  while(GSMSerial.available()>0) 
  {
    Serial.write(GSMSerial.read());//Forward what Software Serial received to Serial Port
    if (Serial.read() > 0) {
      userInput =(Serial.read());
      Serial.println(userInput);
    }
    
  }
  
}

void newcode() {
  char receivedMsg[100];//size for max message
char textMessage[5];//size appropriately for parsed characters
boolean newMessage = false;
boolean prefixMatch = false;


  while (GSMSerial.available() > 0)
  {
    //readBytes returns number read not zero referenced
    byte numChars = GSMSerial.readBytes(receivedMsg, 100);
    receivedMsg[numChars] = '\0';//null Terminate
    newMessage = true;
  }
  //can define a series of prefix messages for match
  
  if (strncmp(receivedMsg, "+CMT", 4) == 0 && newMessage == true)
  {
    Serial.println("prefixMatch +CMT");
    prefixMatch = true;
    newMessage = false;
  }
  else if (newMessage == true)
  {
    Serial.println("no prefixMatch");
    Serial.println(receivedMsg);
    newMessage = false;
  }
  if (prefixMatch == true)
  {
    prefixMatch = false;
    char* index;
    //find last " with strrchr()
    index = strrchr(receivedMsg, '"');
    strcpy(textMessage,index+1);//copies from after " pointer to ending null
    Serial.print("Text message = ");
    Serial.println(textMessage);
  }
}

Serial Monitor outputs:

Initializing…
AT

OK
AT+CMGF=1

OK
AT+CNMI=1,2,0,0,0

OK
no prefixMatch

+CMT: “+447980XXXXX7”,"",“20/06/07,09:17:59+04”
Test text

I don't have an 800L to test with, and when I adapt your code for input from the Serial Monitor I see the prefix match.
I think that there is some non printing character before the prefix(perhaps a '\n' or '\r') before the message. strncmp which is looking for the prefix match starts with the first character, and if it is not the + then the match won't occur.
Try this change which uses strstr() which just looks for +CMT anywhere in the message. If this works we can try and figure out why the previous match was not seen.

//if (strncmp(receivedMsg, "+CMT", 4) == 0 && newMessage == true)
  if (strstr(receivedMsg, "+CMT") != 0 && newMessage == true)

So using the new strstr nailed it. And it actually works exactly how i want it to so no need for further investigation.
I did however investigate further cause curious and in case someone else comes across the same issue.

Adding either '\n' or '\r' before CMT does not resolve. must be some other character or something weird happening.

I'm happy to continue testing if you have other suggestions and are curious too, but as i mentioned, your strstr fix solved the problem for what i need it for.

Thanks Cattledog

I’m curious. Lets see what’s at the start of the message.

while (GSMSerial.available() > 0)
  {
    //readBytes returns number read not zero referenced
    byte numChars = GSMSerial.readBytes(receivedMsg, 100);
    receivedMsg[numChars] = '\0';//null Terminate
    newMessage = true;
    for(byte i = 0; i < 10; i++)
    {
      Serial.println((byte)receivedMsg[i]);
    }
  }

You have this code below as part of updateSerial(). I’m not certain why you would nest a Serial.read() statement in a GSMSerial.availalbe() conditional. What are you trying to achieve with this. I’m sure there is a better way. Furthermore userInput is a String object(with capital S) and it would be better to not have it in the program.

while(GSMSerial.available()>0)
  {
    Serial.write(GSMSerial.read());//Forward what Software Serial received to Serial Port
    if (Serial.read() > 0) {
      userInput =(Serial.read());
      Serial.println(userInput);
    }
   
  }

I like your style.

So first 2 bytes are 13 and 10. so carriage return then new line feed. Then goes into +CMT.

As for the update Serial function; it was remnants from an old code that was working to setup the GSM at the beginning. I basically used it to mirror Serial and GSMSerial.

It worked so i left it in in fear it would stop haha.

Spice

So first 2 bytes are 13 and 10. so carriage return then new line feed. Then goes into +CMT.

That’s what I thought. I will change my example for future use.

When I look at this SMS tutorial on General Syntax I see that

Syntax rule 4. Information responses and result codes (including both final result codes and unsolicited result codes) always start and end with a carriage return character and a linefeed character.

Example: After sending the command line “AT+CGMI” to the mobile device, the mobile device should return a response similar to this:

Nokia
OK

Here’s the next one then Cattledog:

Everything works in standalone code.

As soon as i try to implement the GSM code into my larger project; it freaks out.

It looks like; instead of sending all characters correctly, some get ‘lost in translation’. Unfortunately being the one i need - the last ".

I can probably just count along the bytes & start grabbing at the message start, but thought you might have an insight or be curious to solve it.

(FYI, I am only wanting to grab the 1st 4 letters of every message)

GSM code is:

#include <SoftwareSerial.h>

SoftwareSerial GSMSerial(7, 8);
char letter1;
char letter2;
char letter3;
char letter4;
void setup()
{
  Serial.begin(9600);
  GSMSerial.begin(9600);
  Serial.println("Initializing..."); 
  delay(1000);
  GSMSerial.println("AT"); //Once the handshake test is successful, it will back to OK
  updateSerial();
  GSMSerial.println("AT+CMGF=1"); // Configuring TEXT mode
  updateSerial();
  GSMSerial.println("AT+CNMI=1,2,0,0,0");
  updateSerial();
}

void loop()
{
  newcode();
}

void updateSerial()
{
  delay(500);
  while (Serial.available()>0) 
  {
    GSMSerial.write(Serial.read());//Forward what Serial received to Software Serial Port
  }
  while(GSMSerial.available()>0) 
  {
    Serial.write(GSMSerial.read());//Forward what Software Serial received to Serial Port
    
  }
  
}
void getGSM() {
while (GSMSerial.available() > 0) //If there is stuff in the buffer
  {
    char textMessage[60] = {}; //size this buffer for the expected message
    byte numChars = GSMSerial.readBytes(textMessage, 5);//readBytes returns number read
    textMessage[numChars] = '\0';//null Terminator
    Serial.println(textMessage); //
}
}

void newcode() {
  char receivedMsg[100];//size for max message
char textMessage[5];//size appropriately for parsed characters
boolean newMessage = false;
boolean prefixMatch = false;


  while (GSMSerial.available() > 0)
  {
    //readBytes returns number read not zero referenced
    byte numChars = GSMSerial.readBytes(receivedMsg, 100);
    receivedMsg[numChars] = '\0';//null Terminate
    newMessage = true;
  }
  
  //if (strncmp(receivedMsg, "+CMT", 4) == 0 && newMessage == true)
  if (strstr(receivedMsg, "+CMT") != 0 && newMessage == true)
  {
    //Serial.println("prefixMatch +CMT");
    prefixMatch = true;
    newMessage = false;
  }
  else if (newMessage == true)
  {
    Serial.println("no prefixMatch");
    //Serial.println(receivedMsg);
    newMessage = false;
  }
  if (prefixMatch == true)
  {
    prefixMatch = false;
    char* index;
    index = strrchr(receivedMsg, '"');  //find last " with strrchr()
    strcpy(textMessage,index+1);//copies from after " pointer to ending null
    letter1 = textMessage[2];
    letter2 = textMessage[3];
    letter3= textMessage[4];
    letter4 = textMessage[5];
    Serial.print(letter1);
    Serial.print(letter2);
    Serial.print(letter3);
    Serial.print(letter4);
    
  }
}

Which prints: (correctly)

Initializing…
AT

OK
AT+CMGF=1

OK
AT+CNMI=1,2,0,0,0

OK
This

The joined code looks like this: (I had to delete some of the functions from here due to word count, but the issue is before it even gets that far.)

#include <SoftwareSerial.h>
#include <Servo.h>

SoftwareSerial GSMSerial(7, 8);
Servo pan;
Servo tilt;
Servo tap;

char incomingByte;
char letter1;
char letter2;
char letter3;
char letter4;
int posPan;
int posTilt;
int posTap;
int Letter;
int movements [28][4] = {{97,63,105,17},{98,100,55,20},{99,77,65,21},
                        {100,75,81,20},{101,79,101,20},{102,85,79,20},
                        {103,93,75,20},{104,103,70,20},{105,118,75,20},
                        {106,115,68,20},{107,120,68,20},{108,130,70,20},
                        {109,123,51,20},{110,113,51,20},{111,125,77,20},
                        {112,135,80,20},{113,65,115,16},{114,85,92,17},
                        {115,68,92,20},{116,93,90,16},{117,112,75,20},
                        {118,87,65,20},{119,70,110,16},{120,71,72,20},
                        {121,100,85,16},{122,63,85,20},{32,100,45,13},
                        {46,138,60,20}};


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

  Serial.println("Initializing..."); 
  delay(1000);

  GSMSerial.println("AT"); //Once the handshake test is successful, it will back to OK
  updateSerial();
  
  GSMSerial.println("AT+CMGF=1"); // Configuring TEXT mode
  updateSerial();
  GSMSerial.println("AT+CNMI=1,2,0,0,0"); // Decides how newly arrived SMS messages should be handled
  updateSerial();

  pan.attach(9);
  tilt.attach(10);
  tap.attach(11);

  pan.write(90); //intialise servos to center
  tilt.write(90);
  tap.write(90);
}

void loop()
{
  letter1=""; //initialise letter1
  letter2=""; //initialise letter2
  letter3=""; //initialise letter3
  letter4="";
  getGSM();
  letter1Select(); //find letter in letter1 and move to it
  letter2Select(); //find letter in letter2 and move to it
  letter3Select(); //find letter in letter3 and move to it
  letter4Select();
  resetArms();  
}

void updateSerial()
{
  delay(500);
  while (Serial.available()>0) 
  {
    GSMSerial.write(Serial.read());
  }
  while(GSMSerial.available()>0) 
  {
    Serial.write(GSMSerial.read());
  }
}

void getGSM() {
  boolean newMessage = false;
  boolean prefixMatch = false;
  char receivedMsg[100];//size for max message
  char textMessage[5];//size appropriately for parsed characters

  while (GSMSerial.available() > 0)
  {
    byte numChars = GSMSerial.readBytes(receivedMsg, 100);
    receivedMsg[numChars] = '\0';//null Terminate
    newMessage = true;
  } 
  //if (strncmp(receivedMsg, "+CMT", 4) == 0 && newMessage == true)
  if (strstr(receivedMsg, "+CMT") != 0 && newMessage == true)
  {
    //Serial.println("prefixMatch +CMT");
    prefixMatch = true;
    newMessage = false;
  }
  else if (newMessage == true)
  {
    Serial.println("no prefixMatch");
    Serial.println(receivedMsg);
    newMessage = false;
  }
  if (prefixMatch == true)
  {
    prefixMatch = false;
    char* index;
    index = strrchr(receivedMsg, '"');  //find last " with strrchr()
    strcpy(textMessage,index+1);//copies from after " pointer to ending null
    letter1 = textMessage[2];
    letter2 = textMessage[3];
    letter3= textMessage[4];
    letter4 = textMessage[5];
    Serial.print(letter1);
    Serial.print(letter2);
    Serial.print(letter3);
    Serial.print(letter4);
    
  }
}
void letter1Select(){
  //byte key1 = letter1;
  byte b = 29;
  while (b>0) {b--;
    if (letter1==movements[b][0]){
      tapLetter(movements[b][1],movements[b][2],movements[b][3]); break;
    };
  };
};

and prints:

Initializing…
AT

OK
AT+CMGF=1

OK
AT+CNMI=1,2,0,0,0

OK
/06/

So I printed receivedMsg to see the issue

+CMT: “+447980xxxxxx”,"","20/06/08,12:56:09+
/06/

So the last " is causing issues. Just wondering what the solution would be to print correctly whether it freaks or not? Maybe I use the last + character and index+2?

You are making some fundamental errors with your character arrays which need to be fixed before you go further. You are reading and writing to memory locations outside of areas you have reserved and this can create unpredictable issues. So, before going further lets fix this. I’m not clear at this point if the missing " is actually due to this, but the memory management needs to addressed first.

I am only wanting to grab the 1st 4 letters of every message

Maybe I use the last + character and index+2?

There is a before the text so the message actually does start at index +3 after the last ".

Arrays are zero indexed. So when you declare char textMessage[5] the actual array indexes are 0,1,2,3,4. For example

char textMessage[5] = "test"; //4 characters plus a null terminator
textMessage[0] = 't'
textMessage[1] = 'e'
textMessage[2] = 's'
textMessage[3] = 't'
textMessage[4] = '\0'

Try getGSM like this and see if the first 4 characters are consistently read. I’ve added an early print out, and changed strcpy() to strncpy() to control the size of the copy if there is some error and there is not a null to stop the copy at the 5th position.

void getGSM() {
  boolean newMessage = false;
  boolean prefixMatch = false;
  char receivedMsg[100];//size for max message
  char textMessage[5];//size appropriately for parsed characters

  while (GSMSerial.available() > 0)
  {
    byte numChars = GSMSerial.readBytes(receivedMsg, 100);
    receivedMsg[numChars] = '\0';//null Terminate
    newMessage = true;
    Serial.println(receivedMsg); //add print out here to verify original message 
  }
  //if (strncmp(receivedMsg, "+CMT", 4) == 0 && newMessage == true)
  if (strstr(receivedMsg, "+CMT") != 0 && newMessage == true)
  {
    //Serial.println("prefixMatch +CMT");
    prefixMatch = true;
    newMessage = false;
  }
  else if (newMessage == true)
  {
    Serial.println("no prefixMatch");
    Serial.println(receivedMsg);
    newMessage = false;
  }
  if (prefixMatch == true)
  {
    prefixMatch = false;
    char* index;
    index = strrchr(receivedMsg, '"');  //find last " with strrchr()
    //strcpy(textMessage,index+1);//copies from after " pointer to ending null
       strncpy(textMessage, index+3, 4); //copy 4 characters into textMessage after the <CR><LF>
    textMessage[4] = '\0';//guarantee null terminator
    letter1 = textMessage[0];
    letter2 = textMessage[1];
    letter3 = textMessage[2];
    letter4 = textMessage[3];
    Serial.print(letter1);
    Serial.print(letter2);
    Serial.print(letter3);
    Serial.print(letter4);
  }
}

You can also make your declarations and initializations consistent here.

char letter1;
char letter2;
char letter3;
char letter4;

The value of a char is set using ’ ’ single quotation marks. The “” double quotations are for character strings. You can put a blank space between the two ’ marks to initialize to an cleared value.

  //letter1=""; //initialise letter1
 // letter2=""; //initialise letter2
 // letter3=""; //initialise letter3
 // letter4="";

  letter1= ' '; //initialise  to a blank space
  letter2= ' '; 
  letter3= ' '; 
  letter4= ' ';

I see that you are planning to use Servo.h along with SoftwareSerial.h.

There is an issue with timer conflict. See this thread.

You may want to google "softwareserial.h and servo.h arduino" and see more.

ok so,

I had a little read of the timing issues between servo.h and softwareserial.h, and heard someone talking about not having to attach and detach mid code… which I thought was a fine work around… and actually seems to help.
Originally when I amended for your new code it returned “no prefix match”; but after changing when i attach the servos; it now works.

The issue I have with using :

letter1= ’ '; //initialise to a blank space

is that a space is actually one of the characters that I am looking for. so it sends it into a loop of tapping space bar.

As it stands it actually all works as I want it to. Its just a bit temperamental and unreliable. but I can restart and reupload, and have a fully working project. So thanks cattledog!

I’m getting the red ~ across the bottom before it uploads my sketch correctly. I assume that’s due to syntax errors or my memory issues you were mentioning?

Other than that I can only assume its because the cheapy 800L i bought is dodgy.

Here is the code as it stands currently (I wasnt sure where you meant to move the char letter1; initialisers to.

#include <SoftwareSerial.h>
#include <Servo.h>
#include <String.h>

SoftwareSerial GSMSerial(7, 8); //SIM800L Tx & Rx is connected to Arduino #7 & #8
Servo pan;
Servo tilt;
Servo tap;

char incomingByte;
char letter1;
char letter2;
char letter3;
char letter4;
int posPan;
int posTilt;
int posTap;
int Letter;
int movements [28][4] = {{97,63,105,17},{98,100,55,20},{99,77,65,21},
                        {100,75,81,20},{101,79,101,20},{102,85,79,20},
                        {103,93,75,20},{104,103,70,20},{105,118,75,20},
                        {106,115,68,20},{107,120,68,20},{108,130,70,20},
                        {109,123,51,20},{110,113,51,20},{111,125,77,20},
                        {112,135,80,20},{113,65,115,16},{114,85,92,17},
                        {115,68,92,20},{116,93,90,16},{117,112,75,20},
                        {118,87,65,20},{119,70,110,16},{120,71,72,20},
                        {121,100,85,16},{122,63,85,20},{32,100,45,13},
                        {46,138,60,20}};


void setup()
{
  //Begin serial communication with Arduino and Arduino IDE (Serial Monitor)
  Serial.begin(9600);
  
  //Begin serial communication with Arduino and SIM800L
  GSMSerial.begin(9600);

  Serial.println("Initializing..."); 
  delay(1000);

  GSMSerial.println("AT"); //Once the handshake test is successful, it will back to OK
  updateSerial();
  
  GSMSerial.println("AT+CMGF=1"); // Configuring TEXT mode
  updateSerial();
  GSMSerial.println("AT+CNMI=1,2,0,0,0"); // Decides how newly arrived SMS messages should be handled
  updateSerial();

  
}

void loop()
{
  letter1=""; //initialise letter1
  letter2=""; //initialise letter2
  letter3=""; //initialise letter3
  letter4="";
  getGSM();
  letter1Select(); //find out which letter is in letter1 and move to it
  letter2Select(); //find out which letter is in letter1 and move to it
  letter3Select(); //find out which letter is in letter1 and move to it
  letter4Select();
  resetArms();  
}

void updateSerial()
{
  delay(500);
  while (Serial.available()>0) 
  {
    GSMSerial.write(Serial.read());//Forward what Serial received to Software Serial Port
  }
  while(GSMSerial.available()>0) 
  {
    Serial.write(GSMSerial.read());//Forward what Software Serial received to Serial Port
  }
}

void getGSM() {
  boolean newMessage = false;
  boolean prefixMatch = false;
  char receivedMsg[100];//size for max message
  char textMessage[5];//size appropriately for parsed characters

  while (GSMSerial.available() > 0)
  {
    byte numChars = GSMSerial.readBytes(receivedMsg, 100);
    receivedMsg[numChars] = '\0';//null Terminate
    newMessage = true;
    Serial.println(receivedMsg); //add print out here to verify original message
  }
  //if (strncmp(receivedMsg, "+CMT", 4) == 0 && newMessage == true)
  if (strstr(receivedMsg, "+CMT") != 0 && newMessage == true)
  {
    //Serial.println("prefixMatch +CMT");
    prefixMatch = true;
    newMessage = false;
  }
  else if (newMessage == true)
  {
    Serial.println("no prefixMatch");
    Serial.println(receivedMsg);
    newMessage = false;
  }
  if (prefixMatch == true)
  {
    prefixMatch = false;
    char* index;
    index = strrchr(receivedMsg, '"');  //find last " with strrchr()
    //strcpy(textMessage,index+1);//copies from after " pointer to ending null
       strncpy(textMessage, index+3, 4); //copy 4 characters into textMessage after the <CR><LF>
    textMessage[4] = '\0';//guarantee null terminator
    strlwr(textMessage); //lowercase all
    letter1 = textMessage[0];
    letter2 = textMessage[1];
    letter3 = textMessage[2];
    letter4 = textMessage[3];
    Serial.print(letter1);
    Serial.print(letter2);
    Serial.print(letter3);
    Serial.print(letter4);

    pan.attach(9);
  tilt.attach(10);
  tap.attach(11);

  pan.write(90); //intialise servos to center
  tilt.write(90);
  tap.write(90);
  }
}
void letter1Select(){
  //byte key1 = letter1;
  byte b = 29;
  while (b>0) {b--;
    if (letter1==movements[b][0]){
      tapLetter(movements[b][1],movements[b][2],movements[b][3]); break;
    };
  };
};

void letter2Select(){
  //byte key1 = letter1;
  byte b = 29;
  if (letter2 != 0){
  while (b>0) {b--;
    if (letter2==movements[b][0]){
      tapLetter(movements[b][1],movements[b][2],movements[b][3]); break;
    };
  };
}};

void letter3Select(){
  //byte key1 = letter1;
  byte b = 29;
  if (letter3 != 0){
  while (b>0) {b--;
    if (letter3==movements[b][0]){
      tapLetter(movements[b][1],movements[b][2],movements[b][3]); break;
    };
  };
}};

void letter4Select(){
  //byte key1 = letter1;
  byte b = 29;
  if (letter4 != 0){
  while (b>0) {b--;
    if (letter4==movements[b][0]){
      tapLetter(movements[b][1],movements[b][2],movements[b][3]); break;
    };
  };
}};

void tapLetter(int a, int b, int c){
  if (a <= 89){
      for (posPan =90; posPan >=a; posPan -= 1){
          pan.write(posPan);
          delay(40);
      }}
  else if (a >= 91){
    for (posPan =90; posPan <=a; posPan += 1){
      pan.write(posPan);
      delay(40);
      }
  }
  if (b<=89){
     for (posTap =90; posTap >=b; posTap -= 5){
      tap.write(posTap);
      delay(40);
      }}
  else if (b >=91){
      for (posTap =90; posTap <=b; posTap += 5){
      tap.write(posTap);
      delay(40);
      }};
      if (c<=89){
    for (posTilt =90; posTilt >=c; posTilt -= 10){
      tilt.write(posTilt);
      delay(40);
      }
    for (posTilt =c; posTilt <=90; posTilt += 4){
      tilt.write(posTilt);
      delay(40);
      }}
      else if (c>=91){
    for (posTilt =90; posTilt <=c; posTilt += 10){
      tilt.write(posTilt);
      delay(40);
      }
    for (posTilt =c; posTilt >=90; posTilt -= 4){
      tilt.write(posTilt);
      delay(40);
      }}

  if (posPan <=89){
  for (posPan =a; posPan <=90; posPan += 5){
      pan.write(posPan);
      delay(40);
}}
  else if (posPan >=91){
    for (posPan =a; posPan >=90; posPan -=5){
      pan.write(posPan);
      delay(40);
    }}}

  void resetArms(){
    //Serial.println("reset");
    pan.write(90);
    delay(80);
    tilt.write(90);
    delay(80);
    tap.write(90);
    delay(80);

    pan.detach();
  tilt.detach();
  tap.detach();
  };

is that a space is actually one of the characters that I am looking for.

Yes, now I see that movements[26] contains 32.

There is actually a compiler warning when the initialization is with the double quotes.
You can clear the letters with anything which is not one of the 28 movement index values you compare, and you will recognize as a default if there is an error. Perhaps the * (ascii 42) would work.

  letter1 = '*';//""; //initialise letter1
  letter2 = '*';//""; //initialise letter2
  letter3 = '*';//""; //initialise letter3
  letter4 = '*';//"";

I think you are making an array boundary error in all your search routines. Remember array indexes start at 0, and go up to one less than the number of elements in the array.

int movements [28][4]

There are 28 arrays of 4 ints, but the index of the 28 arrays is 0 through 27. Your routine starts the search at index 28, which is likely to contain garbage, but may have a matching value at random.

void letter1Select() {
  //byte key1 = letter1;
  byte b = 28; //29;
  while (b > 0) {
    b--;//first index will be 27
    if (letter1 == movements[b][0]) {
      tapLetter(movements[b][1], movements[b][2], movements[b][3]); break;
    };
  };
};

I had a little read of the timing issues between servo.h and softwareserial.h, and heard someone talking about not having to attach and detach mid code... which I thought was a fine work around... and actually seems to help.
Originally when I amended for your new code it returned "no prefix match"; but after changing when i attach the servos; it now works.

I'm not certain that attaching and detaching the servo is the best way to manage the timer conflict and it will limit when you can send a message.

I'm getting the red ~ across the bottom before it uploads my sketch correctly. I assume that's due to syntax errors or my memory issues you were mentioning?

Explain more about this, as I don't see issues when I compile or upload the code.

As it stands it actually all works as I want it to. Its just a bit temperamental and unreliable

Explain more about this as well and we can work to improve the performance.

I'm unclear if you really want to be calling the four letterNSelect() every pass through loop if there is no new letter available.

So the main issue i seem to be having is that once a message has been sent, the program loops round with 'no prefix match'. I assume this is because the GSMSerial, which usually waits for >0, is now reading something left over?

So the main issue i seem to be having is that once a message has been sent, the program loops round with 'no prefix match'. I assume this is because the GSMSerial, which usually waits for >0, is now reading something left over?

Your hypothesis is reasonable. Does it loop around multiple times, or just once? Is it possible that the entire message response is greater than the 100 characters, and its being read in two parts?

The no prefix match section is primarily for testing and debug, and if you are receiving all the +CMT responses in entirety to the messages you send and there are no other messages you are interested in, the section can be removed.

If you want to get to the root cause of the looping, you have to do some more investigation.

You have Serial print statements in the code when a message is first received and again in the no prefix match block. What do they tell you?

If nothing is being printed out it maybe non printable junk, try to patch in the technique used in post #10 to read byte by byte to see what is there.