Sprintf Confusion

Hello,
I'm messing around with a SIM7600 cellular board and am trying to understand some code that I found for it on the internet. The board is working, in that I can send "AT+" type commands to it and can get the board to send an email to my phone. However, all of the code that I've found "hard-codes" the commands into the program. What I am trying to do is to understand how to use the Sprintf command in order to put the AT+ commands into variables (actually CONST char) and then call the variable.

Here is an example of a command that "works":

char aux_str[70];
const char smtp_server[ ] = "mail.smtp2go.com";          // SMTP server
const char smtp_port[ ] = "587";                                        // SMTP server port

sprintf(aux_str, "AT+SMTPSRV=\"%s\",%s", smtp_server, smtp_port);  
Serial.println(aux_str);

I get the following on the Arduino Com Port:

AT+SMTPSRV="mail.smtp2go.com",587   which is actually what I want to be printed to the display. 

However the way I want to do it is to put the "AT+SMTPSRV=" string into a CONST CHAR, something like:

atPlusSmtpSrv[ ] = "AT+SMTPSRV=";

I've tried this a bunch of different ways including all of the following:
``
sprintf(aux_str, atPlusSmtpSrv "%s",%s", smtp_server, smtp_port);

sprintf(aux_str, atPlusSmtpSrv, smtp_server, smtp_port);

sprintf(aux_str, atPlusSmtpSrv "%s" %s", smtp_server, smtp_port);

sprintf(aux_str, atPlusSmtpSrv "%s",%s", smtp_server, smtp_port);


This one comes the closest:
`sprintf(aux_str, "atPlusSmtpSrv \"%s\",%s", smtp_server, smtp_port);`

However, it produces the following result:

atPlusSmtpSrv "mail.smtp2go.com",587 

My problem is that I can't find an sprintf syntax explanations that are relevant to my situation.

Here's what I think I know:
1. "aux_str" is the array into which the "assembled string" will be placed, and will be displayed on the com terminal via the Serial.println command

2. Sprintf properly assembles the "AT+SMTPSRV=" string, the "mail.smtp2go.com" string, and the "587" from the variable "SMTP_Port".

3. It seems to me that several variations (listed above) that I've tried should work.  However, each of them has its own problem, whether the problem is a failure to complete the "aux_str" assembly or failure to grab the actual AT+ command from the variable and then append the server and port data to it.

I'm sure I'm missing something here and would appreciate it if someone would point out what is likely to be obvious.  I'd also appreciate it if you might point me to a reasonably thorough explanation of sprintf.

Thanks in advance.,
Robert

Do you mean this?

const char atPlusSmtpSrv[] = "AT+SMTPSRV=";
// ...

sprintf(aux_str, "%s\"%s\",%s", atPlusSmtpSrv, smtp_server, smtp_port);  

You may want to have a look at the documentation of sprintf and the format string (containing the magic %s stuff).

sprintf(aux_str, "AT+SMTPSRV=%s, %s", smtp_server, smtp_port);

You can't modify a variable declared "const", but it is possible to put the string into a variable declared as a character array.

char buf[50];
snprintf(buf,sizeof(buf), "AT+SMTPSRV="%s,%s", smtp_server, smtp_port);

I think @jfjlaros nailed it.

A slightly different variation would be

char aux_str[70];
const char smtp_server[ ] = "mail.smtp2go.com";          // SMTP server
const char smtp_port[ ] = "587";                                        // SMTP server port
const char atPlusSmtpSrv[ ] = "AT+SMTPSRV=\"%s\",%s";

sprintf(aux_str, atPlusSmtpSrv, smtp_server, smtp_port);  
Serial.println(aux_str);

Oh, I had all the "%s'"s in the wrong spot? I'll give it a try. As for the sprintf documentation I will definitely read it and try to understand it. I'll also pay attention to where it's located, because I didn' find it when I looked he first time.

Hello ZX80, yes, I think that's the way it was in the original code that I was trying to modify. That definitely works but I was trying to learn something rather than just copying the guy's code without trying to understand it.

Yes, that's what I was attempting to do at the top of my original message

I tried your solution as well as PaulRB's. Both worked well. My next job is to figure out why I couldn't see this in the first place.

Thanks to all who helped,
Robert

The sprintf() function is a standard function in the C++ language. So any C++ reference will have it along with all the other string functions of string.h

Yes, I knew that, and that's where I looked. However, the ones that I saw did not have much of an explanation. I specifically googled "sprintf".

This should be better than my first example.

  const char atPlusSmtpSrv[ ] = "AT+SMTPSRV=";
  const char smtp_server[ ] = "mail.smtp2go.com";
  int smtp_port= 587;
  sprintf(aux_str, "%s%s, %d", atPlusSmtpSrv, smtp_server, smtp_port);
  Serial.println(aux_str);

Why sprintf? A function with a couple of arguments and serial prints works as well and is less resource hungry.

The code in post #5 uses

  Sketch uses 3030 bytes (9%) of program storage space. Maximum is 30720 bytes.
  Global variables use 298 bytes (14%) of dynamic memory, leaving 1750 bytes for local variables. Maximum is 2048 bytes.

This code
```cpp
char aux_str[70];
const char smtp_server[ ] = "\"mail.smtp2go.com\"";          // SMTP server
const char smtp_port[ ] = "587";                             // SMTP server port
const char *atCmd = "AT+SMTPSRV=";

void setup()
{
  Serial.begin(115200);
  sendAT(atCmd, smtp_server, smtp_port);
}

void loop()
{
}

void sendAT(const char *cmd, const char *param1, const char *param2)
{
  Serial.print(cmd);
  if (param1 != NULL)
  {
    Serial.print(param1);
  }
  if (param2 != NULL)
  {
    Serial.print(",");
    Serial.println(param2);
  }
}

uses

  Sketch uses 1544 bytes (5%) of program storage space. Maximum is 30720 bytes.
  Global variables use 224 bytes (10%) of dynamic memory, leaving 1824 bytes for local variables. Maximum is 2048 bytes.

The difference in RAM usage is due to the omission of aux_str as you don't have to allocate a buffer for it.

Note

  1. I'm not familiar with AT commands but you might get the idea how to expand.
  2. The difference can be crucial if your microcontroller has very limited RAM (e.g. Uno).

Why sprintf? Because it seemed like a good idea at the time! lol Seriously speaking, I didn't know any other way to do it besides trying to "build" a string from various pieces. But you hit the nail on the head--I'm running out of dynamic memory and was trying to be careful not to burn it up--that's why I used CONST chars rather than just initializing variables. I do realize though that it would have been less resource intensive if I had just done it the way the original author did and just hard-coded the AT commands into the lines themselves. But I saw it as an opportunity to learn something. But you're absolutely right--I will go back and modify my code to do as you suggest.

And while I'm on the subject, I've been reading the literature and trying to figure out the function of the %s in the offered solutions--well, specifically the "%s" implementation. I understand %s by itself, and have found references to say, \n and \r, where the \ is combined with the n or r to form particular meanings. However, I haven't found anything that addresses the backslash by itself, or whether in this case it is used as part of a larger meaning of some sort. Can you point me in the direction I should go to learn about it?

Strings use double quotes at start and end. If you need a double quote in your string, you have to escape it else the compiler will think that it's the end of the string; that is the use of the backslash.

To put a literal backslash in your string you have to escape it as well, so you get '\'.

Otherwise, a single backslash indicates that the next character has a special meaning. E.g. a 't' after a backslash indicates that it's the tab character, a 'n' a new line, a 'r' a carriage return.

I'm not sure of a good reference, probably a search for c-string in combination with escape will get you what you want to know.

Thank you, your information is of great value to me--I assumed that the backslash was some kind of delimiter, I just couldn't find anything that talked about it. I appreciate your having taken the time to reply.

C++ escape sequences.

This is a situation akin to picking yourself up by your own bootlaces. ie, if you know that the backslash is the escape character then the detail is easy to find. However, if you don't know that then you don't know what to search for. egg/chicken !

Another factor in finding out what the backslash does/means when using sprintf() is that it is not specific to sprintf() or any of the other variations or print formatting functions

Once you know about the escape character you can use it in a multitude of ways as it the usual way with C/C++

Precisely! I don't know how I would have ever found escape sequences if I hadn't been told of their existence. Thanks to all of you!

Last thing: Escape sequences are very straightforward once one knows what to look for!