MKR GSM1400 storing SMS to memory

confusing the heck out of myself now especially with the remotenumber part for making the call, would be really nice if I could visualise this graphically, may be able to understand what being saved where where it should go...

also I realise I have not added the "+" yet but was saving that for a Friday headache challenge

/*
  /*
  Receive number by SMS and make Voice Calls to that number a specified number of times


  Modified Aug 2019
  by Dano with help from J-M-L and the rest of the Arduino Forum

*/
#include <MKRGSM.h> //this is the MKR GSM library
const char PINNUMBER[] = "0000"; //SIM Pin although the MKR GSM voice call example has a seperate SECRET tab for entering this

// initialize the library instances
GSM gsmAccess;
GSM_SMS sms; //required to receive an SMS
GSMVoiceCall vcs; //required to make a voice call

String remoteNumber = "";  // the number you will call, this is somewhat confusing as this is the calling number in the "make voice call" example in the library
char charbuffer[20];

// Array to hold the number a SMS is retreived from
char senderNumber[20];//this is not required but useful for fault finding or identifying unexpected SMS from other sources

// Array to hold the text of the SMS
const byte maxSMSLength = 50;
char smsMessageBody[maxSMSLength + 1];






void setup() {
  // initialize serial communications and wait for port to open:
  Serial.begin(115200);//check this is the same in the monitor
  while (!Serial) ;

  // Start GSM connectionx
  bool connected = false;
  while (!connected) {
    if (gsmAccess.begin(PINNUMBER) == GSM_READY) {
      connected = true;
    } else {
      Serial.write('.');
      delay(1000);
    }
  }

  Serial.println("GSM initialized");
  Serial.println("Waiting for messages");
}






void loop() {
  int c;

  // If there are any SMSs available()
  if (sms.available()) {
    Serial.println("Message received from:");

    // Get remote number
    sms.remoteNumber(senderNumber, 20);
    Serial.println(senderNumber);

    // Read message bytes and print them
    int i = 0;
    while (((c = sms.read()) != -1) && (i < maxSMSLength)) {
      smsMessageBody[i++] = c;
    }
    smsMessageBody[i] = '\0'; // terminate the cString correctly

    Serial.print(F("Received:"));
    Serial.println(smsMessageBody);//all working fine until here

    // Delete message from modem memory
    sms.flush();


    // this is now where you need to parse the SMS body.
    // assume the format is "+447771871234, 20"
    // here this is a crude parser, with no test for error
    // parse using strtok: http://www.cplusplus.com/reference/cstring/strtok/
    

    strtok (smsMessageBody, "+"); // replace the + by a NULL CHAR
    const char * phoneNumberToCallPtr = strtok (NULL, ","); // replace the ',' by a NULL char, pointer after the ','
    const char * totalNumberOfCallsPtr = strtok (NULL, ""); // we just want the next pointer

    // transform the string into a number http://www.cplusplus.com/reference/cstdlib/atoi/
    

    const int totalNumberOfCalls = atoi(totalNumberOfCallsPtr);
    Serial.print(F("Calling [+"));//does not appear to work from this point

    Serial.print(phoneNumberToCallPtr); // carefull we removed the +
    Serial.print(F("] for "));
    Serial.print(totalNumberOfCalls);
    Serial.print(F(" times"));

    for (int callNb = 0; callNb < totalNumberOfCalls; callNb++) {
      Serial.print(F("Call #"));
      Serial.print(callNb + 1);

      // HERE PUT THE CODE TO PLACE A CALL
      // remember to add the + in the dialing

      // (see example in https://www.arduino.cc/en/Reference/GSMVCSVoiceCall)
      // Call the remote number


      remoteNumber.toCharArray(charbuffer, 20);


      // Check if the receiving end has picked up the call
      
	if (vcs.voiceCall(charbuffer))
      {
        Serial.println("Call Established. Enter line to end");
        // Wait for some input from the line
        while (Serial.read() != '\n' && (vcs.getvoiceCallStatus() == TALKING));
        // And hang up
        vcs.hangCall();
      }
    }

    delay(1000);

  }
}

so the part of this that is not working I think is the strtok function because it prints "Calling (+) for 0 times" so this leads me to believe that phoneNumberToCallPtr and totalNumberOfCallsPtr are not being saved or have been replaced somehow, the fact that it doesn't call the number indicates it missing also

NB if I use square brackets around the plus sign the forum converts that to a bullet, in the monitor it shows square brackets on the same line

// this is now where you need to parse the SMS body.
    // assume the format is "+447771871234, 20"
    // here this is a crude parser, with no test for error
    // parse using strtok: http://www.cplusplus.com/reference/cstring/strtok/
    

    strtok (smsMessageBody, "+"); // replace the + by a NULL CHAR
    const char * phoneNumberToCallPtr = strtok (NULL, ","); // replace the ',' by a NULL char, pointer after the ','
    const char * totalNumberOfCallsPtr = strtok (NULL, ""); // we just want the next pointer

    // transform the string into a number http://www.cplusplus.com/reference/cstdlib/atoi/
    

    const int totalNumberOfCalls = atoi(totalNumberOfCallsPtr);
    Serial.print(F("Calling [+"));//does not appear to work from this point

    Serial.print(phoneNumberToCallPtr); // carefull we removed the +
    Serial.print(F("] for "));
    Serial.print(totalNumberOfCalls);
    Serial.print(F(" times"));

    for (int callNb = 0; callNb < totalNumberOfCalls; callNb++) {
      Serial.print(F("Call #"));
      Serial.print(callNb + 1);

Have you tried my first code as is and sent an sms with exactly the following text:

Hello +4412345678,20 some stuff

What do you see in the console? As I said I don’t have access to my kits at the moment so code is just typed here - might be buggy

J-M-L the first code needs to be pasted into the receive SMS example right? I appended the setup and removed the loop but this will not compile, gives me a specific error "Error compliing for board Arduino MKR GSM 1400"

Dan

No my code should be self sufficient unless I've typos

#include <MKRGSM.h>
const char PINNUMBER[] = "0000"; // << REPLACE WITH YOU PIN

// initialize the library instances
GSM gsmAccess;
GSM_SMS sms;

// Array to hold the number a SMS is retreived from
char senderNumber[20];

// Array to hold the text of the SMS
const byte maxSMSLength = 50;
char smsMessageBody[maxSMSLength + 1];

void setup() {
  // initialize serial communications and wait for port to open:
  Serial.begin(115200);
  while (!Serial) ;

  // Start GSM connectionx
  bool connected = false;
  while (!connected) {
    if (gsmAccess.begin(PINNUMBER) == GSM_READY) {
      connected = true;
    } else {
      Serial.write('.');
      delay(1000);
    }
  }

  Serial.println("GSM initialized");
  Serial.println("Waiting for messages");
}

void loop() {
  int c;

  // If there are any SMSs available()
  if (sms.available()) {
    Serial.println("Message received from:");

    // Get remote number
    sms.remoteNumber(senderNumber, 20);
    Serial.println(senderNumber);

    // Read message bytes and print them
    int i = 0;
    while (((c = sms.read()) != -1) && (i < maxSMSLength)) {
      smsMessageBody[i++] = c;
    }
    smsMessageBody[i] = '\0'; // terminate the cString correctly

    Serial.print(F("Received:"));
    Serial.println(smsMessageBody);

    // Delete message from modem memory
    sms.flush();


    // this is now where you need to parse the SMS body.
    // assume the format is "+YYxxxxxxxxxxx, 20"
    // here this is a crude parser, with no test for error

    // parse using strtok: http://www.cplusplus.com/reference/cstring/strtok/
    strtok (smsMessageBody, "+"); // replace the + by a NULL CHAR
    const char * phoneNumberToCallPtr = strtok (NULL, ","); // replace the ',' by a NULL char, pointer after the ','
    const char * totalNumberOfCallsPtr = strtok (NULL, ""); // we just want the next pointer

    // transform the string into a number http://www.cplusplus.com/reference/cstdlib/atoi/
    const int totalNumberOfCalls = atoi(totalNumberOfCallsPtr);

    Serial.print(F("Calling [+"));
    Serial.print(phoneNumberToCallPtr); // carefull we removed the +
    Serial.print(F("] for "));
    Serial.print(totalNumberOfCalls);
    Serial.print(F(" times"));

    for (int callNb = 0; callNb < totalNumberOfCalls; callNb++) {
      Serial.print(F("Call #"));
      Serial.print(callNb + 1);

      // HERE PUT THE CODE TO PLACE A CALL
      // remember to add the + in the dialing
      // (see example in https://www.arduino.cc/en/Reference/GSMVCSVoiceCall)

    }
  }

  delay(1000);

}

this should decode the SMS you are sending - but not doing anything smart with it as the loop for making the calls is empty

if you are 100% sure that the SMS you will send will be well formatted with just the number to call, a comma and the number of repetition, you can even simplify the parsing (which then will get the +) with finding where the comma is and that's it.

you can use strchr() to find the pointer to the comma, replace the comma by a '\0' and then add 1 to that pointer and pass that to atoi()
here is a quick example on how to use strchr()

// Array to hold the text of the SMS
const byte maxSMSLength = 100;
char smsMessageBody[maxSMSLength + 1];

void setup() {
  Serial.begin(115200);
  // simulate receiving the SMS
  strcpy(smsMessageBody, "+4412345678,20");

  char* const phoneNumberToCallPtr = smsMessageBody;
  char* const commaPointer = strchr(smsMessageBody, ','); // http://www.cplusplus.com/reference/cstring/strchr/
  if (commaPointer != NULL) {
    *commaPointer = '\0'; // put a NULL char there so that we have a well formed cString for the phone number
    // transform the string into a number http://www.cplusplus.com/reference/cstdlib/atoi/
    const int totalNumberOfCalls = atoi(commaPointer + 1); // we parse what's after the comma

    Serial.print(F("Calling ["));
    Serial.print(phoneNumberToCallPtr);
    Serial.print(F("] for "));
    Serial.print(totalNumberOfCalls);
    Serial.print(F(" times"));
  } else Serial.println(F("No comma, error. SMS format has to be +CCxxxxxxxxxx,nn"));

}

void loop() {}

Hi J-M-L for the first code the result is the same,

it prints the number sending the SMS,
prints the received SMS as "Received:+447771871234, 10"
and then prints "Calling [plus sign] for 0 times"

so it doesnt seem to save the number or retrieve it, I cannot see anything obvious in the code but then I am out of my depth here

I will try the second one now

Dan

I have tried to merge both of those examples into the read SMS and voicecall examples, there is still the issue of either reading/saving the SMS content or writing it so I am not even able to determine of the rest of the code will make the voice call which I do not believe it will because of the "remoteNumber" string

getting very confused now, any assistance would be very much appreciated

/*
  receive SMS, extract content and call number specified number of times
*/

// libraries
#include <MKRGSM.h>

// Please enter your sensitive data in the Secret tab or arduino_secrets.h
// PIN Number
const char PINNUMBER[] = SECRET_PINNUMBER;

// initialize the library instances
GSM gsmAccess;
GSM_SMS sms;
GSMVoiceCall vcs;

String remoteNumber = "";  // the number you will call
char charbuffer[20];
// Array to hold the number a SMS is retreived from
char senderNumber[20];
// Array to hold the text of the SMS
const byte maxSMSLength = 50;
char smsMessageBody[maxSMSLength + 1];


void setup() {

  // initialize serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  Serial.println("SMS Messages Receiver");

  // connection state
  bool connected = false;

  // Start GSM shield
  // If your SIM has PIN, pass it as a parameter of begin() in quotes
  while (!connected) {
    if (gsmAccess.begin(PINNUMBER) == GSM_READY) {
      connected = true;
    } else {
      Serial.println("Not connected");
      delay(1000);
    }
  }

  Serial.println("GSM initialized.");
  Serial.println("Waiting for messages");


}

void loop() {
  int c;

  // If there are any SMSs available()
  if (sms.available()) {
    Serial.println("Message received from:");

    // Get remote number
    sms.remoteNumber(senderNumber, 20);
    Serial.println(senderNumber);

    // Read message bytes and print them
    int i = 0;
    while (((c = sms.read()) != -1) && (i < maxSMSLength)) {
      smsMessageBody[i++] = c;
    }
    smsMessageBody[i] = '\0'; // terminate the cString correctly

    Serial.print(F("Received:"));
    Serial.println(smsMessageBody);

    // Delete message from modem memory
    sms.flush();


    // this is now where you need to parse the SMS body.
    // assume the format is "+YYxxxxxxxxxxx, 20"
    // here this is a crude parser, with no test for error

    // parse using strtok: http://www.cplusplus.com/reference/cstring/strtok/
    strtok (smsMessageBody, "+"); // replace the + by a NULL CHAR
    const char * phoneNumberToCallPtr = strtok (NULL, ","); // replace the ',' by a NULL char, pointer after the ','
    const char * totalNumberOfCallsPtr = strtok (NULL, ""); // we just want the next pointer

    // transform the string into a number http://www.cplusplus.com/reference/cstdlib/atoi/
    const int totalNumberOfCalls = atoi(totalNumberOfCallsPtr);

    Serial.print(F("Calling [+"));
    Serial.print(phoneNumberToCallPtr); // carefull we removed the +
    Serial.print(F("] for "));
    Serial.print(totalNumberOfCalls);
    Serial.print(F(" times"));

    for (int callNb = 0; callNb < totalNumberOfCalls; callNb++) {
      Serial.print(F("Call #"));
      Serial.print(callNb + 1);

      // HERE PUT THE CODE TO PLACE A CALL
      // remember to add the + in the dialing
      // (see example in https://www.arduino.cc/en/Reference/GSMVCSVoiceCall)

    }
  }

  delay(1000);

}



// add any incoming characters to the String:
while (Serial.available() > 0) {
  char inChar = Serial.read();
  // if it's a newline, that means you should make the call:
  if (inChar == '\n') {
    // make sure the phone number is not too long:
    if (remoteNumber.length() < 20) {
      // let the user know you're calling:
      Serial.print("Calling to : ");
      Serial.println(remoteNumber);
      Serial.println();

      // Call the remote number
      remoteNumber.toCharArray(charbuffer, 20);


      // Check if the receiving end has picked up the call
      if (vcs.voiceCall(charbuffer)) {
        Serial.println("Call Established. Enter line to end");
        // Wait for some input from the line
        while (Serial.read() != '\n' && (vcs.getvoiceCallStatus() == TALKING));
        // And hang up
        vcs.hangCall();
      }
      Serial.println("Call Finished");
      remoteNumber = "";
      Serial.println("Enter phone number to call.");
    } else {
      Serial.println("That's too long for a phone number. I'm forgetting it");
      remoteNumber = "";
    }
  } else {
    // add the latest character to the message to send:
    if (inChar != '\r') {
      remoteNumber += inChar;
    }
  }
}
}

I don't understand why J-M-L's example is not working correctly and there appears to be an issue with the persistence of the multiple pointers. When I test his code on a Uno in a non GSM context but using software serial from the monitor it parses and prints correctly.

That said, I have always used strtok with a single pointer and strcpy to secondary char arrays for use in the code. See if this approach preserves the parsed message. If this is successful, I would add code to clear, rather than overwrite, the transfer strings each time there is a new message.

/*
  receive SMS, extract content and call number specified number of times
*/

// libraries
#include <MKRGSM.h>

// Please enter your sensitive data in the Secret tab or arduino_secrets.h
// PIN Number
const char PINNUMBER[] = SECRET_PINNUMBER;

// initialize the library instances
GSM gsmAccess;
GSM_SMS sms;
GSMVoiceCall vcs;

String remoteNumber = "";  // the number you will call
char charbuffer[20];
// Array to hold the number a SMS is retreived from
char senderNumber[20];
// Array to hold the text of the SMS
const byte maxSMSLength = 50;
char smsMessageBody[maxSMSLength + 1];

char phoneNumberToCall[16];//size for parsed characters
char numberOfCalls[4];//size for parsed characters

void setup() {
  // initialize serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  Serial.println("SMS Messages Receiver");

  // connection state
  bool connected = false;

  // Start GSM shield
  // If your SIM has PIN, pass it as a parameter of begin() in quotes
  while (!connected) {
    if (gsmAccess.begin(PINNUMBER) == GSM_READY) {
      connected = true;
    } else {
      Serial.println("Not connected");
      delay(1000);
    }
  }

  Serial.println("GSM initialized.");
  Serial.println("Waiting for messages");
}

void loop() {
  int c;
  // If there are any SMSs available()
  if (sms.available()) {
    Serial.println("Message received from:");

    // Get remote number
    sms.remoteNumber(senderNumber, 20);
    Serial.println(senderNumber);

    // Read message bytes and print them
    int i = 0;
    while (((c = sms.read()) != -1) && (i < maxSMSLength)) {
      smsMessageBody[i++] = c;
    }
    smsMessageBody[i] = '\0'; // terminate the cString correctly

    Serial.print(F("Received:"));
    Serial.println(smsMessageBody);

    // Delete message from modem memory
    sms.flush();

    // this is now where you need to parse the SMS body.
    // assume the format is "+YYxxxxxxxxxxx, 20"
    // here this is a crude parser, with no test for error

    // parse using strtok: http://www.cplusplus.com/reference/cstring/strtok/
    strtok (smsMessageBody, "+"); // replace the + by a NULL CHAR
    char* strtokIndx;
    //const char * phoneNumberToCallPtr = strtok (NULL, ","); // replace the ',' by a NULL char, pointer after the ','
    strtokIndx = strtok (NULL, ","); // replace the ',' by a NULL char, pointer after the ','
    strcpy(phoneNumberToCall, strtokIndx);
    //const char * totalNumberOfCallsPtr = strtok (NULL, ""); // we just want the next pointer
    strtokIndx = (NULL, ""); // we just want the next pointer
    strcpy(numberOfCalls, strtokIndx);
    // transform the string into a number http://www.cplusplus.com/reference/cstdlib/atoi/
    //const int totalNumberOfCalls = atoi(totalNumberOfCallsPtr);

    int totalNumberOfCalls = atoi(numberOfCalls);


    Serial.print(F("Calling [+"));
    //Serial.print(phoneNumberToCallPtr); // carefull we removed the +
    Serial.print(phoneNumberToCall);
    Serial.print(F("] for "));
    Serial.print(totalNumberOfCalls);
    Serial.print(F(" times"));

    for (int callNb = 0; callNb < totalNumberOfCalls; callNb++) {
      Serial.print(F("Call #"));
      Serial.print(callNb + 1);

      // HERE PUT THE CODE TO PLACE A CALL
      // remember to add the + in the dialing
      // (see example in https://www.arduino.cc/en/Reference/GSMVCSVoiceCall)

    }
  }
  delay(1000);
}

// add any incoming characters to the String:
while (Serial.available() > 0) {
  char inChar = Serial.read();
  // if it's a newline, that means you should make the call:
  if (inChar == '\n') {
    // make sure the phone number is not too long:
    if (remoteNumber.length() < 20) {
      // let the user know you're calling:
      Serial.print("Calling to : ");
      Serial.println(remoteNumber);
      Serial.println();

      // Call the remote number
      remoteNumber.toCharArray(charbuffer, 20);


      // Check if the receiving end has picked up the call
      if (vcs.voiceCall(charbuffer)) {
        Serial.println("Call Established. Enter line to end");
        // Wait for some input from the line
        while (Serial.read() != '\n' && (vcs.getvoiceCallStatus() == TALKING));
        // And hang up
        vcs.hangCall();
      }
      Serial.println("Call Finished");
      remoteNumber = "";
      Serial.println("Enter phone number to call.");
    } else {
      Serial.println("That's too long for a phone number. I'm forgetting it");
      remoteNumber = "";
    }
  } else {
    // add the latest character to the message to send:
    if (inChar != '\r') {
      remoteNumber += inChar;
    }
  }
}
}

smsMessageBody Is already a persistent global copy of the sms data.

Having multiple pointers into that buffer should not be wiped. I’m sure they are not. That being said I’m on the go and can’t test code (but you seem to indicate it works OK on a UNO)

Dan - can you 100% confirm you are using the code I posted - with no tweaks?

J-M-L:
smsMessageBody Is already a persistent global copy of the sms data.

Having multiple pointers into that buffer should not be wiped. I’m sure they are not. That being said I’m on the go and can’t test code (but you seem to indicate it works OK on a UNO)

Dan - can you 100% confirm you are using the code I posted - with no tweaks?

Hi J-M-L I am using the first code you shared exactly as you posted, the second code I pasted into the make voicecall example as suggested, I believe its correct although I suspect the actually string used for remotenumber may be incorrect, its a bit beyond my skill level to determine if that would work but as far as serial print after the parse it does not show the number as expected

I will have a go at the example above from cattledog and report back

cattledog:
I don't understand why J-M-L's example is not working correctly and there appears to be an issue with the persistence of the multiple pointers. When I test his code on a Uno in a non GSM context but using software serial from the monitor it parses and prints correctly.

That said, I have always used strtok with a single pointer and strcpy to secondary char arrays for use in the code. See if this approach preserves the parsed message. If this is successful, I would add code to clear, rather than overwrite, the transfer strings each time there is a new message.

Hi cattledog, I get the following the following error in this case
exit status 1
invalid conversion from 'const char*' to 'char*' [-fpermissive]

I do not understand that but will have a google

Dan

I do believe that remoteNumber is somehow conflicting here, could this be overwriting the string or char somehow?

the strtokIndx line 89 is creating the invalid conversion from 'const char*' to 'char*' [-fpermissive] but I cannot as of yet determine why

I may have omitted to mention that the phone number in the SMS can be a variable length, ie +447771871234 or +46709701234 or +8615111541234

Hi cattledog, I get the following the following error in this case
exit status 1
invalid conversion from 'const char*' to 'char*' [-fpermissive]

//char* strtokIndx;
const char* strtokIndx;

Were getting into areas I don't understand. I'm not clear why we are seeing this error, as typically when using strtok with a UNO and received messages you can use char*.

I see this on Stack Exchange

char* is a mutable pointer to a mutable character/string.

const char* is a mutable pointer to an immutable character/string. You cannot change the contents of the location(s) this pointer points to. Also, compilers are required to give error messages when you try to do so. For the same reason, conversion from const char * to char* is deprecated.

The error may be a clue, since I don't understand why the message being parsed is considered an "immutable" string which causes the error.

char smsMessageBody[maxSMSLength + 1];

strtok definitely modifies the message and replaces the index characters with nulls.

I'm confused as to the error, and the MKR1400 environment.

cattledog:

//char* strtokIndx;

const char* strtokIndx;

unless I am misunderstanding your guidance I had already tried that but unfortunately it made little difference

/*
  receive SMS, extract content and call number specified number of times
*/

// libraries
#include <MKRGSM.h>

// Please enter your sensitive data in the Secret tab or arduino_secrets.h
#define SECRET_PINNUMBER     ""

// PIN Number
const char PINNUMBER[] = SECRET_PINNUMBER;

// initialize the library instances
GSM gsmAccess;
GSM_SMS sms;
GSMVoiceCall vcs;

// the number you will call
String remoteNumber = "";
char charbuffer[20];
// Array to hold the number a SMS is retreived from
char senderNumber[20];
// Array to hold the text of the SMS
const byte maxSMSLength = 50;
char smsMessageBody[maxSMSLength + 1];
//size for parsed characters
char phoneNumberToCall[16];
//size for parsed characters
char numberOfCalls[4];

void setup() {
  // initialize serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ;
    // wait for serial port to connect. Needed for native USB port only
  }
  Serial.println("SMS Messages Receiver");
  // connection state
  bool connected = false;
  // Start GSM shield
  // If your SIM has PIN, pass it as a parameter of begin() in quotes (not required if using SECRETS tab)
  while (!connected) {
    if (gsmAccess.begin(PINNUMBER) == GSM_READY) {
      connected = true;
    } else {
      Serial.println("Not connected");
      delay(1000);
    }
  }
  Serial.println("GSM initialized.");
  Serial.println("Waiting for messages");
}

void loop() {
  int c;
  // If there are any SMSs available()
  if (sms.available()) {
    Serial.println("Message received from:");
    // Get remote number
    sms.remoteNumber(senderNumber, 20);
    Serial.println(senderNumber);
    // Read message bytes and print them
    int i = 0;
    while (((c = sms.read()) != -1) && (i < maxSMSLength)) {
      smsMessageBody[i++] = c;
    }
    // terminate the cString correctly
    smsMessageBody[i] = '\0';
    Serial.print(F("Received:"));
    Serial.println(smsMessageBody);
    // Delete message from modem memory
    sms.flush();
    // this is now where you need to parse the SMS body.
    // assume the format is "+YYxxxxxxxxxxx, 20"
    // here this is a crude parser, with no test for error
    // parse using strtok: http://www.cplusplus.com/reference/cstring/strtok/
    // replace the + by a NULL CHAR
    strtok (smsMessageBody, "+");
    //    changed from char* strtokIndx;
    const char* strtokIndx;
    // replace the ',' by a NULL char, pointer after the ','
    const char * phoneNumberToCallPtr = strtok (NULL, ",");
    // replace the ',' by a NULL char, pointer after the ','
    strtokIndx = strtok (NULL, ",");
    strcpy(phoneNumberToCall, strtokIndx);
    // we just want the next pointer
    const char* totalNumberOfCallsPtr = strtok (NULL, "");
    // we just want the next pointer
    strtokIndx = (NULL, "");
    strcpy(numberOfCalls, strtokIndx);
    // transform the string into a number http://www.cplusplus.com/reference/cstdlib/atoi/
    //const int totalNumberOfCalls = atoi(totalNumberOfCallsPtr);
    int totalNumberOfCalls = atoi(numberOfCalls);
    Serial.print(F("Calling [+"));
    //Serial.print(phoneNumberToCallPtr); // carefull we removed the +
    Serial.print(phoneNumberToCall);
    Serial.print(F("] for "));
    Serial.print(totalNumberOfCalls);
    Serial.print(F(" times"));
    for (int callNb = 0; callNb < totalNumberOfCalls; callNb++) {
      Serial.print(F("Call #"));
      Serial.print(callNb + 1);
      // HERE PUT THE CODE TO PLACE A CALL
      // remember to add the + in the dialing
      // (see example in https://www.arduino.cc/en/Reference/GSMVCSVoiceCall)
    }
  }
  delay(1000);
  // add any incoming characters to the String:
  while (Serial.available() > 0) {
    char inChar = Serial.read();
    // if it's a newline, that means you should make the call:
    if (inChar == '\n') {
      // make sure the phone number is not too long:
      if (remoteNumber.length() < 20) {
        // let the user know you're calling:
        Serial.print("Calling to : ");
        Serial.println(remoteNumber);
        Serial.println();
        // Call the remote number
        remoteNumber.toCharArray(charbuffer, 20);
        // Check if the receiving end has picked up the call
        if (vcs.voiceCall(charbuffer)) {
          Serial.println("Call Established. Enter line to end");
          // Wait for some input from the line
          while (Serial.read() != '\n' && (vcs.getvoiceCallStatus() == TALKING));
          // And hang up
          vcs.hangCall();
        }
        Serial.println("Call Finished");
        remoteNumber = "";
        Serial.println("Enter phone number to call.");
      } else {
        Serial.println("That's too long for a phone number. I'm forgetting it");
        remoteNumber = "";
      }
    } else {
      // add the latest character to the message to send:
      if (inChar != '\r') {
        remoteNumber += inChar;
      }
    }
  }
}

this is what I see in the serial monitor

16:43:07.514 -> SMS Messages Receiver
16:43:17.702 -> GSM initialized.
16:43:17.702 -> Waiting for messages
16:43:30.127 -> Message received from:
16:43:30.127 -> +31620541234
16:43:30.127 -> Received:+447771871234, 5
16:43:30.166 -> Calling [(plus sign)⸮(backwards question mark)] for 0 times

cattledog:
Were getting into areas I don't understand. I'm not clear why we are seeing this error, as typically when using strtok with a UNO and received messages you can use char*.

I see this on Stack Exchange

The error may be a clue, since I don't understand why the message being parsed is considered an "immutable" string which causes the error.

char smsMessageBody[maxSMSLength + 1];

strtok definitely modifies the message and replaces the index characters with nulls.

I'm confused as to the error, and the MKR1400 environment.

could well be its the MKR GSM 1400, I did read somewhere that its a different build but I do not understand how that it would require alternative programming, that is also way beyond my skill level

I don't believe you did this as I intended. You need to comment out the previously used pointers from JML's code, and make the strcpy right after the strtok call.

strtok (smsMessageBody, "+"); // replace the + by a NULL CHAR
    const char* strtokIndx;
    strtokIndx = strtok (NULL, ","); 
    strcpy(phoneNumberToCall, strtokIndx);
    strtokIndx = (NULL, ""); // we just want the next pointer
    strcpy(numberOfCalls, strtokIndx);
    // transform the string into a number
    int totalNumberOfCalls = atoi(numberOfCalls);

exactly the same result when replaced as you stated

/*
  receive SMS, extract content and call number specified number of times
*/

// libraries
#include <MKRGSM.h>

// Please enter your sensitive data in the Secret tab or arduino_secrets.h
#define SECRET_PINNUMBER     ""

// PIN Number
const char PINNUMBER[] = SECRET_PINNUMBER;

// initialize the library instances
GSM gsmAccess;
GSM_SMS sms;
GSMVoiceCall vcs;

// the number you will call
String remoteNumber = "";
char charbuffer[20];
// Array to hold the number a SMS is retreived from
char senderNumber[20];
// Array to hold the text of the SMS
const byte maxSMSLength = 50;
char smsMessageBody[maxSMSLength + 1];
//size for parsed characters
char phoneNumberToCall[16];
//size for parsed characters
char numberOfCalls[4];

void setup() {
  // initialize serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ;
    // wait for serial port to connect. Needed for native USB port only
  }
  Serial.println("SMS Messages Receiver");
  // connection state
  bool connected = false;
  // Start GSM shield
  // If your SIM has PIN, pass it as a parameter of begin() in quotes (not required if using SECRETS tab)
  while (!connected) {
    if (gsmAccess.begin(PINNUMBER) == GSM_READY) {
      connected = true;
    } else {
      Serial.println("Not connected");
      delay(1000);
    }
  }
  Serial.println("GSM initialized.");
  Serial.println("Waiting for messages");
}

void loop() {
  int c;
  // If there are any SMSs available()
  if (sms.available()) {
    Serial.println("Message received from:");
    // Get remote number
    sms.remoteNumber(senderNumber, 20);
    Serial.println(senderNumber);
    // Read message bytes and print them
    int i = 0;
    while (((c = sms.read()) != -1) && (i < maxSMSLength)) {
      smsMessageBody[i++] = c;
    }
    // terminate the cString correctly
    smsMessageBody[i] = '\0';
    Serial.print(F("Received:"));
    Serial.println(smsMessageBody);
    // Delete message from modem memory
    sms.flush();
    // this is now where you need to parse the SMS body.
    // assume the format is "+YYxxxxxxxxxxx, 20"
    // here this is a crude parser, with no test for error
    // parse using strtok: http://www.cplusplus.com/reference/cstring/strtok/
    // replace the + by a NULL CHAR
    
    // replace the + by a NULL CHAR
    strtok (smsMessageBody, "+"); 
    const char* strtokIndx;
    strtokIndx = strtok (NULL, ","); 
    strcpy(phoneNumberToCall, strtokIndx);
    // we just want the next pointer
    strtokIndx = (NULL, ""); 
    strcpy(numberOfCalls, strtokIndx);
    // transform the string into a number
    int totalNumberOfCalls = atoi(numberOfCalls);
    
    /*
    this section replaced with suggested code from cattledog above
    strtok (smsMessageBody, "+");
    //    changed from char* strtokIndx;
    const char* strtokIndx;
    // replace the ',' by a NULL char, pointer after the ','
    const char * phoneNumberToCallPtr = strtok (NULL, ",");
    // replace the ',' by a NULL char, pointer after the ','
    strtokIndx = strtok (NULL, ",");
    strcpy(phoneNumberToCall, strtokIndx);
    // we just want the next pointer
    const char* totalNumberOfCallsPtr = strtok (NULL, "");
    // we just want the next pointer
    strtokIndx = (NULL, "");
    strcpy(numberOfCalls, strtokIndx);
    // transform the string into a number http://www.cplusplus.com/reference/cstdlib/atoi/
    //const int totalNumberOfCalls = atoi(totalNumberOfCallsPtr);
    int totalNumberOfCalls = atoi(numberOfCalls);*/
    
    Serial.print(F("Calling [+"));
    //Serial.print(phoneNumberToCallPtr); // carefull we removed the +
    Serial.print(phoneNumberToCall);
    Serial.print(F("] for "));
    Serial.print(totalNumberOfCalls);
    Serial.print(F(" times"));
    for (int callNb = 0; callNb < totalNumberOfCalls; callNb++) {
      Serial.print(F("Call #"));
      Serial.print(callNb + 1);
      // HERE PUT THE CODE TO PLACE A CALL
      // remember to add the + in the dialing
      // (see example in https://www.arduino.cc/en/Reference/GSMVCSVoiceCall)
    }
  }
  delay(1000);
  // add any incoming characters to the String:
  while (Serial.available() > 0) {
    char inChar = Serial.read();
    // if it's a newline, that means you should make the call:
    if (inChar == '\n') {
      // make sure the phone number is not too long:
      if (remoteNumber.length() < 20) {
        // let the user know you're calling:
        Serial.print("Calling to : ");
        Serial.println(remoteNumber);
        Serial.println();
        // Call the remote number
        remoteNumber.toCharArray(charbuffer, 20);
        // Check if the receiving end has picked up the call
        if (vcs.voiceCall(charbuffer)) {
          Serial.println("Call Established. Enter line to end");
          // Wait for some input from the line
          while (Serial.read() != '\n' && (vcs.getvoiceCallStatus() == TALKING));
          // And hang up
          vcs.hangCall();
        }
        Serial.println("Call Finished");
        remoteNumber = "";
        Serial.println("Enter phone number to call.");
      } else {
        Serial.println("That's too long for a phone number. I'm forgetting it");
        remoteNumber = "";
      }
    } else {
      // add the latest character to the message to send:
      if (inChar != '\r') {
        remoteNumber += inChar;
      }
    }
  }
}