printProgStr Function Error with IDE 1.0.2 and above

I've been out of the Arduino world for a while, but recently came back to update a program that has been running successfully on a couple of Arduinos over the last year. The program is, at it's core, a webserver that accepts specially formatted URL parameters to toggle outputs on an off.

When I was originally writing the sketch, I had issues with space so I fell back to using the F() function to store text strings in flash. The problem I had encountered was that when attempting to send these strings back as part of a response to the web client, each character in the string was begin sent in a new Ethernet packet. With the help of some people here, I found/modified a "printProgStr" function that would allow me to send the strigns stored in flash memory in one packet, and not byte by byte. Here is that function:

void printProgStr (EthernetClient client, __FlashStringHelper * str)
{
  char * p = (char *) str;
  if (!p) return;
  char buf [strlen_P (p) + 1];
  byte i = 0;
  char c;
  while ((c = pgm_read_byte(p++)))
    buf [i++] = c;
  buf [i] = 0;

  client.write(buf);
}

Note, "client" is the currently connected Ethernet client, as this fucntion is only called inside a "while (client.connected())" loop.

To use the function, my program would call something like:

printProgStr(client, F("HTTP/1.1 200 OK\nContent-Type: text/html\n")); //Send back HTTP 200 code

This compiles find in Arduino 1.0 (the latest available at the time I wrote this sketch), and the code uploaded to the Arduino runs as expected. However, now that I've gotten back into the Arduino world I figured I would update to Arduino 1.0.4. When I attempt to compile the code in 1.0.2 or above, I get

error: invalid conversion from 'const __FlashStringHelper*' to '__FlashStringHelper*'

I'm not clear on what the difference between a "const __FlashStringHelper" and a "__FlashStringHelper" is, nor do I understand what changed between 1.0 and 1.0.2 to make this no longer valid. Guidance appreciated.

When I attempt to compile the code in 1.0.2 or above, I get...

Compiles fine for me under 1.0.3...

#include <Dhcp.h>
#include <Dns.h>
#include <Ethernet.h>
#include <EthernetClient.h>
#include <EthernetServer.h>
#include <EthernetUdp.h>
#include <util.h>
#include <SPI.h>

void printProgStr (EthernetClient client, __FlashStringHelper * str)
{
  char * p = (char *) str;
  if (!p) return;
  char buf [strlen_P (p) + 1];
  byte i = 0;
  char c;
  while ((c = pgm_read_byte(p++)))
    buf [i++] = c;
  buf [i] = 0;

  client.write(buf);
}

void setup( void ) {}

void loop( void ) {}

After adding your test call...

#include <Dhcp.h>
#include <Dns.h>
#include <Ethernet.h>
#include <EthernetClient.h>
#include <EthernetServer.h>
#include <EthernetUdp.h>
#include <util.h>
#include <SPI.h>

void printProgStr (EthernetClient client, __FlashStringHelper * str)
{
  char * p = (char *) str;
  if (!p) return;
  char buf [strlen_P (p) + 1];
  byte i = 0;
  char c;
  while ((c = pgm_read_byte(p++)))
    buf [i++] = c;
  buf [i] = 0;

  client.write(buf);
}

void setup( void ) 
{
  printProgStr(client, F("HTTP/1.1 200 OK\nContent-Type: text/html\n")); //Send back HTTP 200 code
}

void loop( void ) {}
sketch_apr09a.ino: In function 'void setup()':
sketch_apr09a:28: error: 'client' was not declared in this scope
sketch_apr09a.ino:28: warning: only initialized variables can be placed into program memory area

Different error message. I suggest you provide a complete example that illustrates the problem.

This is a simplified version of my program (Can't get the whole thing to post or I would have started with that):

#include <SPI.h>
#include <Ethernet.h>

char line1[80]; //Holds HTTP header recieved

EthernetServer server(80); //HTTP server port
byte mac[] = {
  0x00, 0x90, 0x40, 0x37, 0x69, 0xCD}; //MAC address

void setup()
{
  //Disables SD card to avoid SPI problems
  pinMode(4,OUTPUT);
  digitalWrite(4, HIGH);

  //Ethernet.begin(mac, ip); //For non-DHCP
  Ethernet.begin(mac); //For DHCP

  // Start HTTP server
  server.begin();
}

void loop()
{
  // listen for incoming clients
  EthernetClient client = server.available();
  if (client) 
  {
    while (client.connected()) 
    {
      printProgStr(client, F("HTTP/1.1 200 OK\nContent-Type: text/html\n")); //Send back HTTP 200 code
      client.println();

      //Finish the session
      client.flush();
      client.stop();   
    }
  }
}


void printProgStr (EthernetClient client, __FlashStringHelper * str)
{
  char * p = (char *) str;
  if (!p) return;
  char buf [strlen_P (p) + 1];
  byte i = 0;
  char c;
  while ((c = pgm_read_byte(p++)))
    buf [i++] = c;
  buf [i] = 0;

  client.write(buf);
}

I can't get that ^ to compile in 1.0.4, but it does work in 1.0.0.

A minor adjustment to printProgStr...

void printProgStr (EthernetClient client, __FlashStringHelper const * const str)
{
  char * p = (char *) str;
  if (!p) return;
  char buf [strlen_P (p) + 1];
  byte i = 0;
  char c;
  while ((c = pgm_read_byte(p++)))
    buf [i++] = c;
  buf [i] = 0;

  client.write(buf);
}

Well awesome! Hum, so what is it about the original vs. explicitly declaring the "const" type that makes a difference between 1.0 and 1.0.4?

This is the issue that drove the change...

This is the commit...

This is the line of code of interest...
https://github.com/arduino/Arduino/blob/master/hardware/arduino/cores/arduino/WString.h#L38

The const qualifier is correct and should have always been present. More recent versions of the gcc compiler require it for two reasons: 1. PSTR returns a pointer to a const; 2. Flash (PROGMEM) data is required to be const.

With the #866 change mentioned above, the F-macro now returns a pointer to a const so your function (printProgStr) has to accept a pointer to a const.

Very good. Things are working as expected now, and even better, I know why!

Thanks for the help.