-->
Page 1 of 2

Passing PROGMEM into a function that takes const char*

PostPosted: Wed Aug 09, 2017 8:23 pm
by DTrain123
I've been trying to clear up some space in RAM by putting all my String literals into PROGMEM.
For functions that take const __FlashStringHelper* I can use the F() macro to create a __FlashStringHelper* from PROGMEM.

For example Serial extends the Print class and it's println method is overloaded to accept __FlashStringHelper*
Code: Select allSerial.println(F("My String Text goes here"));


However I'm not sure what to do when a function requires a const char* as a parameter.
For example the printf function doesn't accept __FlashStringHelper*
The following code fails to compile.
Code: Select allSerial.printf(F("My name is: %s"), name);


What's the best way to pass data from PROGMEM to a function that requires const char* ?

There are many other functions out there that don't have any idea about __FlashStringHelper, so it would be nice to have an easy macro that could make this work.

Re: Passing PROGMEM into a function that takes const char*

PostPosted: Sun Aug 13, 2017 9:29 pm
by DTrain123
I've managed to come up with this way of doing it. However it's really long winded. It uses the _P methods to create a char[] buffer that is the length of the PROGMEM string, then copies the PROGMEM string into the buffer, then calls the method that takes (const char*) as a parameter, then deletes the buffer.

Code: Select all  static const char PROGMEM WIFI_AP_NAME[] = "My Wifi AP Name";
  static const char PROGMEM WIFI_AP_PASSWORD[] = "My Wifi Password";
  char* apNameBuffer = new char[strlen_P(WIFI_AP_NAME)];
  char* apPasswordBuffer = new char[strlen_P(WIFI_AP_PASSWORD)];
  strcpy_P(apNameBuffer, WIFI_AP_NAME);
  strcpy_P(apPasswordBuffer, WIFI_AP_PASSWORD);
    wifiManager.autoConnect(apNameBuffer, apPasswordBuffer);
  delete [] apNameBuffer;
  delete [] apPasswordBuffer;


However it's not a very nice solution because it's turned one line of code into 9 lines.
It would be much nicer to have a macro that works inline like the F("") macro does so I could just do:

Code: Select all    wifiManager.autoConnect(G("My Wifi AP Name"), G("My Wifi Password"));


Or something similar. Anyone have any ideas?

Re: Passing PROGMEM into a function that takes const char*

PostPosted: Tue Aug 15, 2017 7:28 pm
by gbafamily1
Take a look inside the file pgmspace.h which contains the names of the functions using PROGMEM.

Here is an excerpt with *_P functions.

Code: Select allint memcmp_P(const void* buf1, PGM_VOID_P buf2P, size_t size);
// memccpy_P is only valid when used with pointers to 8bit data, due to size aligned pointers
// and endianess of the values greater than 8bit, matching c may return invalid aligned pointers
void* memccpy_P(void* dest, PGM_VOID_P src, int c, size_t count);
void* memmem_P(const void* buf, size_t bufSize, PGM_VOID_P findP, size_t findPSize);
void* memcpy_P(void* dest, PGM_VOID_P src, size_t count);
char* strncpy_P(char* dest, PGM_P src, size_t size);
#define strcpy_P(dest, src)          strncpy_P((dest), (src), SIZE_IRRELEVANT)
char* strncat_P(char* dest, PGM_P src, size_t size);
#define strcat_P(dest, src)          strncat_P((dest), (src), SIZE_IRRELEVANT)
int strncmp_P(const char* str1, PGM_P str2P, size_t size);
#define strcmp_P(str1, str2P)          strncmp_P((str1), (str2P), SIZE_IRRELEVANT)
int strncasecmp_P(const char* str1, PGM_P str2P, size_t size);
#define strcasecmp_P(str1, str2P)          strncasecmp_P((str1), (str2P), SIZE_IRRELEVANT)
size_t strnlen_P(PGM_P s, size_t size);
#define strlen_P(strP)          strnlen_P((strP), SIZE_IRRELEVANT)
char* strstr_P(const char* haystack, PGM_P needle);
int   printf_P(PGM_P formatP, ...) __attribute__((format(printf, 1, 2)));
int   sprintf_P(char *str, PGM_P formatP, ...) __attribute__((format(printf, 2, 3)));
int   snprintf_P(char *str, size_t strSize, PGM_P formatP, ...) __attribute__((format(printf, 3, 4)));
int   vsnprintf_P(char *str, size_t strSize, PGM_P formatP, va_list ap) __attribute__((format(printf, 3, 0)));

Re: Passing PROGMEM into a function that takes const char*

PostPosted: Wed Aug 16, 2017 11:54 am
by martinayotte
... and in the core/esp8266/Print.h :
Code: Select allsize_t printf_P(PGM_P format, ...) __attribute__((format(printf, 2, 3)));