Issues with strstr_P (PROGMEM)

Hi !

I try to use strstr_P in a big project and can't have it working. My goal is to search in a (RAM) buffer for a string (char*) located in FLASH with PROGMEM. I did write a little and simple sketch which shows the problem, here it is :

void setup() {
  //WITH PROGMEM
  char *foo1 = "With PROGMEM is not working";
  char *foo2 PROGMEM = "is";
  char *foo3 = strstr_P(foo1, foo2);
  
  //WITHOUT PROGMEM
  char *foo4 = "Without PROGMEM is working";
  char *foo5 = "is";
  char *foo6 = strstr(foo4, foo5);
  
  Serial.begin(9600);
  
  //RESULT
  Serial.println(foo3);
  Serial.println(foo6);
  
}

void loop() {
  // put your main code here, to run repeatedly:

}

And here is what I see on the terminal :

is working

I use an Arduino Uno and my IDE is Arduino 1.5.6-r2.

I don't understand why the PROGMEM version doesn't work. The documentation says :

The strstr_P() function finds the first occurrence of the substring s2 in the string s1. [...] The strstr_P() function is similar to strstr() except that s2 is pointer to a string in program space.

Source : http://www.stmental.net/~dfoster/avr-libc-user-manual-1.6.5/group__avr__pgmspace.html#g36c9c2de19d7e23c4a6bf63eee608af3

Then... Why ? :confused:

Try this...

void setup() {
  //WITH PROGMEM
  static char foo1[] = "With PROGMEM is not working";
  static char foo2[] PROGMEM = "is";
  char *foo3 = strstr_P(foo1, foo2);
  
  //WITHOUT PROGMEM
  char *foo4 = "Without PROGMEM is working";
  char *foo5 = "is";
  char *foo6 = strstr(foo4, foo5);
  
  Serial.begin(9600);
  
  //RESULT
  if ( foo3 != NULL )
    Serial.println( foo3 );
  else
    Serial.println( F( "NULL" ) );
  
  Serial.println(foo6);
  
}

void loop() {
  // put your main code here, to run repeatedly:

}

Your version works fine, thanks !

Can you explain me why is the "static" keyword important here ?

Actually, I thought that all PROGMEM var (in FLASH) were static, since the FLASH isn't written during the execution of the program.

I still can't do it with my program anyway because I have a few differences between what I really use in my code and this sketch. Here's a version muc longer but corresponding with what I use :

main sketch .ino

#include "file.h"

static const char *foo PROGMEM = "is";

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  if (Serial.available() > 0)
  {
    char *foo2;
    ble_readSerial();
    Serial.print("Read : ");
    Serial.println(strBleCommand);
    foo2 = strstr_P(strBleCommand, foo);
    Serial.println(foo2);
  }
}

file.cpp

#include "file.h"
#include <Arduino.h>
//VAR
char strBleCommand[BLE_BUFFER_SIZE + 1];

unsigned char ble_readSerial(void)
{
  unsigned char i = 0;
  unsigned long iTime = millis();

  ble_cleanBuffer();

  while (millis() - iTime < 1000 or i >= BLE_BUFFER_SIZE)
  {
    while (Serial.available() > 0)
    {
      char inChar = Serial.read();
      if (inChar == '

file.h

#define BLE_BUFFER_SIZE 30

//VAR
extern char strBleCommand[BLE_BUFFER_SIZE + 1];

unsigned char ble_readSerial(void);
void ble_cleanBuffer(void);

The functions in the .c files are not relevant imo, just some reading and putting in the buffer methods for the Serial. I don't understand why there's nothing in the foo2 var...)
     {
       strBleCommand[i] = '


file.h

§DISCOURSE_HOISTED_CODE_2§


The functions in the .c files are not relevant imo, just some reading and putting in the buffer methods for the Serial. I don't understand why there's nothing in the foo2 var...;
        return 0;
      }
      else if (inChar != '

file.h

§_DISCOURSE_HOISTED_CODE_2_§

The functions in the .c files are not relevant imo, just some reading and putting in the buffer methods for the Serial. I don't understand why there's nothing in the foo2 var... and i <= BLE_BUFFER_SIZE)
     {
       strBleCommand[i] = inChar;
       i++;
     }
     else
     {
       return -1;
     }
   }
 }
 return -1;
}

void ble_cleanBuffer(void)
{
 unsigned char i;
 for (i = 0; i < BLE_BUFFER_SIZE; i++)
 {
   strBleCommand[i] = ' ';
 }
}


file.h

§DISCOURSE_HOISTED_CODE_2§


The functions in the .c files are not relevant imo, just some reading and putting in the buffer methods for the Serial. I don't understand why there's nothing in the foo2 var...

static const char *foo PROGMEM = "is";

...stores the pointer to the string in Flash. The string is stored in SRAM.

static const char foo[] PROGMEM = "is";

...stores the string in Flash. The pointer only exists in the compiler's head.

See the difference?

SwissPotato:
Can you explain me why is the "static" keyword important here ?

Without it the foos exist on the stack.

Actually, I thought that all PROGMEM var (in FLASH) were static, since the FLASH isn't written during the execution of the program

We are discussing a C++ program which means C++ rules still apply. Without the static they are automatic variables which puts them on the stack.