Cannot convert 'StringSumHelper' to 'const char*'

Hi all,

i have a small code issue with converting the strings.
My goal is to use "number1" and give it's value into the function "sendATCommand", along with other String parts.

So the end goal is to send [AT+CPBW=1, "1234",145,"Number1"] to my SIM module.
Unfortunately it doesn't compile, due to the following error:
"Cannot convert 'StringSumHelper' to 'const char*'"
After researching it seems like i have to transform the String into Char array, but the more i read about it, the more confused i get.

Do you know a working (and comprehensible) fix for my problem?

Thank you!

#include <SoftwareSerial.h>

SoftwareSerial SIM7670Serial(2, 3); // RX, TX
String number1="1234";

void setup() {
  Serial.begin(9600);
  SIM7670Serial.begin(9600);
  sendATCommand("AT+CPBW=1,\""+number1+"\",145,\"Number1\"",1000);
}

void loop() {
}

void sendATCommand(const char* cmd, unsigned long timeout) {
  SIM7670Serial.println(cmd);
  String response = "";
  response.reserve(50);
  unsigned long startTime = millis();

  while (millis() - startTime < timeout) {
    while (SIM7670Serial.available() > 0) {
      char c = SIM7670Serial.read();
      response += c;
    }
  }
  Serial.println(response);
  }

You can't build a cString like this

you need a buffer

char commandBuffer[100]; // ensure it's large enough for the largest command

and then you build the content using standard function from stdlib.h or string.h

Using snprintf() makes it somewhat easy

snprintf(commandBuffer, sizeof commandBuffer, "AT+CPBW=1,\"%d"\",145,\"Number1\"", number1); // if number1 is an int

otherwise you use the String class (with caution)

String commandString.c_str = "AT+CPBW=1,\""
commandString += number1;
commandString += "\",145,\"Number1\"";
sendATCommand(commandString.c_str, 1000);

and pass the cString to the function using commandString.c_str() as parameter

c_str() is the answer, but here's another approach. Add this

void sendATCommand(String& cmd, unsigned long timeout) {
  sendATCommand(cmd.c_str(), timeout);
}

This is function overloading. You've probably used it already, with Serial.println. It takes many different types, like int and const char *.

In your sketch, you have just one sendATCommand. So the compiler will try to convert what you have -- the result of + with a String: a StringSumHelper -- to what you asked for: const char* cmd. There is no way to do this automatically, so you get the error.

StringSumHelper is a subclass of String (the exact implementation can vary by board). By declaring this same-name function with a different set of arguments -- along with the return type, it's the function signature -- the compiler can find a match. And for this function variant, you call c_str() to return a const char*, which is what the first function is expecting.

The argument is a String&, which means the argument is passed by reference, to avoid making a copy, which is unnecessary and at least temporarily consumes memory.

Now with two variants, you can call sendATCommand with a plain literal string in quotes, a char buffer, a String, or the result of adding a String to other things.

but not "AT+CPBW=1,\""+number1+"\",145,\"Number1\""

OP still needs to fix this.

Works for me

String number1="1234";

void doSomething(const char* cmd) {
  Serial.println();
  Serial.println("something:");
  Serial.println(cmd);
}

void doSomething(String& cmd) {
  doSomething(cmd.c_str());
}

void setup() {
  Serial.begin(115200);
}

void loop() {
  number1 = millis();
  doSomething("AT+CPBW=1,\""+number1+"\",145,\"Number1\"");
  delay(500);
}

I did not noticed number1 was a String and had assumed it was a number (int, float or the likes)

my bad

Thank guys, i got it working!

  commandString="AT+CPBW=1,\"";
  commandString +=number1;
  commandString +="\",145,\"Number1\"";
  sendATCommand(commandString.c_str(),1000);

Out of curiosity I also tried it without a String class at all using strcat() to combine the char arrays, which also worked.

Sorry, i have to follow up with something.
When i send the standalone command to the module, everything works fine and i get an "OK" back.
But when i'm trying to send it out of my main code, the arduino only sends gibberish to the serial port.

I'm basically sending an SMS to the module and want to save a given number.

if(SIM7670Serial.available()) {
    response.reserve(50);
    while(SIM7670Serial.available()){
    char c = SIM7670Serial.read();  //gets one byte from serial buffer
    response += c; //makes the String readString
    delay(2);  //slow looping to allow buffer to fill with next character
      }
    Serial.println(response);

    if(response.indexOf("RING") != -1) {      // Ringing
      callStatus = 1;
      }  
    if(response.indexOf("BEGIN") != -1) {     // Call connected
      callStatus = 2;
      }
    if(response.indexOf("END") != -1) {       // Call ended
      callStatus = 0;
      }
    if(response.indexOf("##1#") != -1){
      location1 = response.indexOf("##1#");
      location2 = location1 + 4;
      number1 = response.substring(location2);
      commandString="AT+CPBW=1,\"";
      commandString +=number1;
      commandString +="\",145,\"Number1\"";
      sendATCommand(commandString.c_str(),1000);
      Serial.println("Saved Tel.1: "+number1);
      }

What i'm getting on the Monitor:

image

EDIT: After some debugging i found out that the following line is the problem. If i comment it, the command works fine. What's the issue here?

number1 = response.substring(location2);

this is not a great way to read the incoming message

I would suggest to study Serial Input Basics to handle this

Sorry, but i still don't get it.
From what i understand from that blog post, is that one thing i did wrong for sure is to try to save the read chars into a String directly, instead of into a char array like in example 2.
So i tried to create an adapted new function for the serial read like that:

void readResponse(){
  if(SIM7670Serial.available()){
    response="";
    static byte ndx = 0;
    response.reserve(100);
    while(SIM7670Serial.available()){
      char c = SIM7670Serial.read(); 
      responseChar[ndx]=c;
      ndx++;
      delay(2); 
      }
    response = String.valueOf(responseChar);
    Serial.println(response);
    }
  }

My thought was to save everything into a char array and then convert it to a String, since i will the String class later on (for the function .substring()).
Unfortunately the code will not compile:

Compilation error: expected primary-expression before '.' token

you can use a String to accumulate the incoming bytes, it's just a buffer at the end of the day (and your use of reserve protects somewhat against undesirable effect of memory fragmentation issues in the heap in some cases) but the challenge is in the way you try to second guess the timing of an asynchronous communication protocol

You do

while(SIM7670Serial.available()){
  char c = SIM7670Serial.read();  //gets one byte from serial buffer
  response += c; //makes the String readString
  delay(2);  //slow looping to allow buffer to fill with next character
}

The use of the delay can be an issue.

At 9600 bauds you get ~1 character per ms so by waiting 2ms, if the flow is continuous on the other side you accumulate 2 characters in the buffer and the while loop only unstacks one.

At each turn of the loop you add one byte into the buffer that you don't deal with until later.

If the message is short enough, you won't fill up the 64 byte buffer and all will be fine, you'll get your message but if it's a longer message, then by second guessing the timing you'll have overflown the Rx buffer and lost incoming bytes.

Best is to receive the bytes when they come and detect the end of the transmission (with AT commands it's usually a end of line or "OK\r\n" or something similar) and then deal with the message. That's what the tutorial talks about.

Thank you for explaining, i appreciate it.

The problem i have at the moment is that i'm getting perfect answers in normal operation (sending commands and receiving the answers).
But the gibberish command only happens as soon as i use this line:

number1 = response.substring(location2);

and only in the corresponding AT command.

If i put a defined number (e.g. "1234") in there, it works fine.
So i don't think the bad way to read data from Serial is the issue, but something else i haven't figured out yet...

well you still have the risk but if you receive short enough messages then you won't see it.

why don't you print out to the console response, location2, and number1 and see if it makes sense.

  • By declaring ndx as static, it is never reset to zero and keeps growing forever. If responseChar is an array, that's bad.
  • Because response is global, there may not be a need to repeatedly re-reserve the capacity, unless the capacity is reduced elsewhere; and in that case, why fiddle with capacity? Set it at the desired max size once.
  • char c is copied into responseChar in the loop, but is never NUL-terminated to indicate the end of the string. In that case, the string is could have garbage at the end
  • String.valueOf works in Java for example, but not here
    • Arduino String does not have valueOf
    • Can't use . to call static methods; need to use ::. That's why you got that error.

You're better off

  • reserve the space you need once
  • in the function, assign "" to clear it
  • in the loop, use plain += c to append the character

No conversion to String needed.

After again several hours of frustration and tinkering around with the Serial Objects, i have the feeling the String class is doing me more harm than good.
So i switched my code to char arrays only.
I got it to compile, but it's again outputting (this time different) garbage.

I'm on vacation for 2 weeks now and i will continue again after i return.
But i'll will probably open a new Topic, since this is kind of getting Off-Topic here.

Thank you so far for the help, maybe we will talk again in a few weeks.