String in function parathesis

I have a custom function that looks like:

void atsendbasic(String command){
  
   Serial2.write(command);
    while (!Serial2.available()) continue;
    while (Serial2.available()) {
      char feedback = Serial2.read();
      Serial.print(feedback);
    }
}

I plan to use the function in my main code like so atsendbasic("AT+command/r/n") and I will then read the modem's response and post it to the serial monitor. This approach does not work though. The line where I attempt Serial2.write(command); is giving errors.

Getting error:

exit status 1
no matching function for call to 'HardwareSerial::write(String&)'

I've seen a stack overflow post that appears to solve the problem but it doesn't work for me. Not sure why though. Using this approach my code would look like:

void atsendbasic(const String& command){
  
   Serial2.write(command);
    while (!Serial2.available()) continue;
    while (Serial2.available()) {
      char feedback = Serial2.read();
      Serial.print(feedback);
    }
}

Getting about the same error:

exit status 1
no matching function for call to 'HardwareSerial::write(const String&)'

Does anyone know what I am doing wrong?

Serial.write() writes the value of the bytes or bytes sent to it, but a String is not a series of bytes in that sense, rather it is an object created using the String library

As the error message says, Serial.write() cannot write a String, however, Serial.print() can

command.c_str()

Serial2.print(command);

I read @UKHeliBob suggestion and didn't realize it was indicating this but thanks to @killzone_kid for pointing out this .c_str() I don't know exactly how I would've applied this but I am reading the documentation.

Serial2.write(command.c_str());

void atsendbasic(String command)
{
  Serial2.write(command.c_str());
  Serial2.flush();  // Wait until it is all sent
  while (!Serial2.available()) continue;
  while (Serial2.available()) 
  {
    Serial.print(Serial2.read());
  }
}

I see now how to use the .c_str() functionality. I may add the Serial2.flush command as well. But I am curious as to why the command Serial2.write("AT+CPIN?\r\n"); works but this which looks to me to be the same thing does not?

String command = "AT+CPIN?\r\n";
Serial2.write(command);

Because "AT+CPIN?\r\n" is a c-string literal and .write() has an overload for that. On the other hand your 'command' variable is an instance of the String class and .write() DOES NOT have an overload for that.

Of course there is no real need to create a String which will slow things down and use more memory than really needed - or worse could silently fail if you are low in SRAM


void atSendReallyBasic(const char* command)
{
  Serial2.write(command);
  Serial2.flush();  // Wait until it is all sent
  while (!Serial2.available()) yield();
  while (Serial2.available()) Serial.write(Serial2.read());
}

It is also likely that you’ll empty Serial2 buffer faster than it’s getting filled and thus won’t read the full answer with such a code, esp if the answer is long

This is how I solved the same problem and, in addition, checked the result to see if it said OK or ERROR:

#include <SoftwareSerial.h>

SoftwareSerial ATCommandStream(2, 3);
unsigned long ATComandBaudRate = 19200;

const char * DestinationNumber = "+639xxxxxx057";
const char * SMSMessage = "Test Message";

void setup()
{
  // start th serial communication with the host computer
  Serial.begin(115200);
  while (!Serial);
  delay(200);
  Serial.println("Sketch started.");

  ATCommandStream.begin(ATComandBaudRate);
  Serial.print("ATCommandStream started at baud rate ");
  Serial.println(ATComandBaudRate);

  // Turn on verbose messages
  SendShortCommand("AT+CMEE");

  // Set character set to GSM:
  SendShortCommand("AT+CSCS=\"GSM\"");

  // Set the SMS output to text mode
  SendShortCommand("AT+CMGF=1");

  // Check the phone number type
  SendShortCommand("AT+CSTA?");
  Serial.println("Note: 129=Unknown, 161=National, 145=International, 177=Network Specific");

  // Test for CMGS command support:
  SendShortCommand("AT+CMGS=?");

  SendSMSMessage(DestinationNumber, SMSMessage);

  SendShortCommand("AT"); // Just checking that it responds with OK
}

void loop() {}

bool WaitForResponse()
{
  unsigned long startTime = millis();
  while (millis() - startTime < 5000)
  {
    String reply = ATCommandStream.readStringUntil('\n');
    if (reply.length() > 0)
    {
      Serial.print("Received: \"");
      Serial.print(reply);
      Serial.println("\"");

      if (reply.startsWith("OK"))
        return true;
        
      if (reply.startsWith("ERROR"))
        return false;
    }
  }
  Serial.println("Did not receive OK.");
  return false;
}

bool SendShortCommand(String command)
{
  Serial.print("Sending command: \"");
  Serial.print(command);
  Serial.println("\"");

  ATCommandStream.print(command);
  ATCommandStream.print("\r\n");

  return WaitForResponse();
}

void SendSMSMessage(const char *number, const char *message)
{
  Serial.println("Sending SMS text");

  Serial.print("Sending: ");
  Serial.print("AT+CMGS=\"");
  Serial.print(number);
  Serial.println("\"(CR)");
  Serial.print(message); // The SMS text you want to send
  Serial.println("(EM)");

  ATCommandStream.print("AT+CMGS=\"");  // Send SMS
  ATCommandStream.print(number);
  ATCommandStream.print("\"\r"); // NOTE: Command ends with CR, not CRLF
  ATCommandStream.print(message); // The SMS text you want to send
  ATCommandStream.write(26); // ASCII EndMessage (EM) CTRL+Z character

  WaitForResponse();
}

This is very interesting code. I am doing something similar but instead of using sms I am doing mqtt protocol so the sending or in my case publishing of messages is quite different. But we do have two portions of our main codes that are similar: checking that the modem responds to "AT" and looking for error messages after general AT commands.

As I mentioned one of the first things I do is send "AT" and if there is no response I assume the modem is off and execute a hardware modem boot procedure. The code is still under development, but I am doing some testing today.

void modemverification () {
  Serial2.write("AT\r\n");
  Serial2.flush();  // Wait until it is all sent
  unsigned long timeout1 = millis(); 
  if (Serial2.available() > 0 && millis() - timeout1 <= 60000) {
    char verificationinfo = Serial2.read();
    Serial.println("VERIFIED");
    verified = 1;
  }
  else {
    verified =0;
  }
}

For some of the important AT commands (est PDP context and make SSL connections) I am scanning for errors with this block.

void atsenderrorcheck(String commandcheck){
 Serial2.print(commandcheck);
 Serial2.flush();  // Wait until it is all sent
 while (Serial2.available() > 0){
   static char message[MAX_MESSAGE_LENGTH];
   static unsigned int message_pos = 0;
   char inByte = Serial2.read();
   if ( inByte != '\n' && (message_pos < MAX_MESSAGE_LENGTH - 1) )
   {
     message[message_pos] = inByte;
     message_pos++;
   }
   else
   {
     message[message_pos] = '\0';
     Serial.println(message);
      message_pos = 0;
     if (strcmp(message,"ERROR\r")==0) {
      Serial.println("ERROR DETECTED");
      errorfunction = 1;
     }
     else {
      Serial.println("NO ERROR DETECTED");
      errorfunction =0;
     }
   }  
  }
}