webserver sketch with PROGMEM does not work

Hello All,

I am trying to make led control web server. It is already working ok, but after adding CSS codes, there is too ,much content in RAM, therefore I try to use flash.
First I tried to modify a small example, but does not work.
Nothing happens in browser. On serial debug, I just get this: stÛP@

Here is my code, can somebody please comment what is wrong inside?

Thanks in advance,

#include <SPI.h>
#include <Ethernet.h>
#include <avr/pgmspace.h>

// MAC address from Ethernet shield sticker under board
byte mac[] = { 0x90, 0xA2, 0xDA, 0x0F, 0x1E, 0x03};
IPAddress ip(192, 168, 1, 250); // IP address, may need to change depending on network
EthernetServer server(80);  // create a server at port 80

String HTTP_req;          // stores the HTTP request
int count = 0;

prog_char string_01[] PROGMEM = "HTTP/1.1 200 OK Content-Type: text/html Connection: close";
prog_char string_02[] PROGMEM = "<!DOCTYPE html><html><head><title>Arduino LED Control</title></head><body><h1>LED</h1><p>Test_page.</p></body></html>";

char buffer[150];

void setup()
{
    Ethernet.begin(mac, ip);  // initialize Ethernet device
    server.begin();           // start to listen for clients
    Serial.begin(9600);       // for diagnostics   
}
void loop()
{
  //  count++;
    EthernetClient client = server.available();  // try to get client
   
    if (client) {  // got client?
        boolean currentLineIsBlank = true;
  
        while (client.connected()) {
            
            if (client.available()) {
  
                
                char c = client.read(); // read 1 byte (character) from client
                
                if (HTTP_req.length() < 50 )
                {
                HTTP_req += c;  // save the HTTP request 1 char at a time, butonly for length 50
                }
                
                
                // last line of client request is blank and ends with \n
                // respond to client only after last line received
                if (c == '\n' && currentLineIsBlank) {
                  
                  // Serial.println("start 111");
                            
                  sendProgMemStrings(client, (char*)pgm_read_word(&(string_01)));
                  client.println();
                  sendProgMemStrings(client, (char*)pgm_read_word(&(string_02)));
                  
              
                    HTTP_req = "";    // finished with request, empty string
                    break;
                }
                // every line of text received from the client ends with \r\n
                if (c == '\n') {
                    // last character on line of received text
                    // starting new line with next character read
                    currentLineIsBlank = true;
                } 
                else if (c != '\r') {
                    // a text character was received from client
                    currentLineIsBlank = false;
                }
            } // end if (client.available())
        } // end while (client.connected())
        delay(1);      // give the web browser time to receive the data
        client.stop(); // close the connection
    } // end if (client)
}

void sendProgMemStrings(EthernetClient & client, char *realword)
{
  
    Serial.println("step 2");
    
  strcpy_P(buffer, realword);
  client.println(buffer);
  
}

Why all that trouble with the function ?
Please use: client.println ( string_01 );

The macro ‘F()’ can also be used to create strings in flash.
It is not needed to print that long string at once. You can print it in small steps.

Serial.println(F("<!DOCTYPE html>")):
Serial.println(F("<html>"));

and so on.

The strcpy_P() and the pgm_read_word() get both the pointer from flash, so you are doing it twice. No wait, perhaps the pgm_read_word() gets the first two characters of the address of the address of string_01 (twice the address), uses that as a pointer, and strcpy_P() uses that (wrong) pointer as if it is a pointer to flash and used pgm_read… internally to get the data… Well, something like that.

If you must use a function, pass on the string_01 directly, I think it will be something like a “const char PROGMEM *” or a “PSTR” as parameter.

Below is somebody elses code in which I put the web page part in a single F() macro. There might be a little upload speed advantage putting the the whole page in a single client.print, as each client.print reportedly initiates a new TCP/IP packet. If the web page is very large, it can be put on an SD card.

//get submit box code
//for use with IDE 1.0
//open serial monitor to see what the arduino receives
//use the \ slash to escape the " in the html or use a '
//address will look like http://192.168.1.102:84 when submited
//for use with W5100 based ethernet shields
//note that the below bug fix may be required
// http://code.google.com/p/arduino/issues/detail?id=605

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

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
byte ip[] = { 192, 168, 1, 102 }; // ip in lan
byte gateway[] = { 192, 168, 1, 1 }; // internet access via router
byte subnet[] = { 255, 255, 255, 0 }; //subnet mask
EthernetServer server(84); //server port

String readString;

//////////////////////

void setup(){

 pinMode(5, OUTPUT); //pin selected to control
 pinMode(6, OUTPUT); //pin selected to control
 pinMode(7, OUTPUT); //pin selected to control
 pinMode(8, OUTPUT); //pin selected to control
 //start Ethernet
 Ethernet.begin(mac, ip, gateway, gateway, subnet);
 server.begin();

 //enable serial data print
 Serial.begin(9600);
 Serial.println(F("server text box test1")); // so I can keep track of what is loaded
}

void loop(){
 // Create a client connection
 EthernetClient client = server.available();
 if (client) {
   while (client.connected()) {
     if (client.available()) {
       char c = client.read();

       //read char by char HTTP request
       if (readString.length() < 100) {

         //store characters to string
         readString += c;
         //Serial.print(c);
       }

       //if HTTP request has ended
       if (c == '\n') {

         ///////////////
         Serial.println(readString); //see what was captured

         //now output HTML data header

client.print(F(  //start F() macro
"HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n"
"<HTML>"
"<HEAD>"
"<meta name='apple-mobile-web-app-capable' content='yes' />"
"<meta name='apple-mobile-web-app-status-bar-style' content='black-translucent' />"
"<TITLE>JAVA Page</TITLE>"
"</HEAD>"
"<BODY>"
"<H1>JAVA</H1>"
"<hr />"
"
"
"<FORM ACTION='/' method=get >"
"Enter Code: <INPUT TYPE=TEXT NAME='LED' VALUE='' SIZE='25' MAXLENGTH='50'>
"
"
"
"<input type=submit value='5 ON' style=width:100px;height:45px onClick=location.href='/?on8;'><input type=submit value='5 OFF' style=width:100px;height:45px onClick=location.href='/?off9;'>
"
"<input type=submit value='6 ON' style=width:100px;height:45px onClick=location.href='/?on8;'><input type=submit value='6 OFF' style=width:100px;height:45px onClick=location.href='/?off9;'>
"
"<input type=submit value='7 ON' style=width:100px;height:45px onClick=location.href='/?on8;'><input type=submit value='7 OFF' style=width:100px;height:45px onClick=location.href='/?off9;'>
"
"<input type=submit value='8 ON' style=width:100px;height:45px onClick=location.href='/?on8;'><input type=submit value='8 OFF' style=width:100px;height:45px onClick=location.href='/?off9;'>
"
"</FORM>"
"</BODY>"
"</HTML>"
));   //end F() macro

         delay(1);
         //stopping client
         client.stop();

         /////////////////////
         if(readString.indexOf("5") >0)//checks for on
         {
           digitalWrite(5, HIGH);    // set pin 5 high
           Serial.println(F("Led On"));
         }
         if(readString.indexOf("50") >0)//checks for off
         {
           digitalWrite(5, LOW);    // set pin 5 low
           Serial.println(F("Led Off"));
         }
         
         if(readString.indexOf("6") >0)//checks for on
         {
           digitalWrite(6, HIGH);    // set pin 6 high
           Serial.println(F("Led 6 On"));
         }
         if(readString.indexOf("60") >0)//checks for off
         {
           digitalWrite(6, LOW);    // set pin 6 low
           Serial.println(F("Led 6 Off"));
         }
         
         if(readString.indexOf("7") >0)//checks for on
         {
           digitalWrite(7, HIGH);    // set pin 7 high
           Serial.println(F("Led On"));
         }
         if(readString.indexOf("70") >0)//checks for off
         {
           digitalWrite(7, LOW);    // set pin 7 low
           Serial.println(F("Led Off"));
         }
         
         if(readString.indexOf("8") >0)//checks for on
         {
           digitalWrite(8, HIGH);    // set pin 8 high
           Serial.println(F("Led On"));
         }
         if(readString.indexOf("80") >0)//checks for off
         {
           digitalWrite(8, LOW);    // set pin 8 low
           Serial.println(F("Led Off"));
         }
         //clearing string for next read
         readString="";

       }
     }
   }
 }
}
String HTTP_req;          // stores the HTTP request
int count = 0;

prog_char string_01[] PROGMEM = "HTTP/1.1 2

In the same sketch? Who are you kidding?

Peter_n:
Why all that trouble with the function ?
Please use: client.println ( string_01 );

The macro ‘F()’ can also be used to create strings in flash.
It is not needed to print that long string at once. You can print it in small steps.

Serial.println(F("<!DOCTYPE html>")):

Serial.println(F(""));



and so on.

The strcpy_P() and the pgm_read_word() get both the pointer from flash, so you are doing it twice. No wait, perhaps the pgm_read_word() gets the first two characters of the address of the address of string_01 (twice the address), uses that as a pointer, and strcpy_P() uses that (wrong) pointer as if it is a pointer to flash and used pgm_read... internally to get the data... Well, something like that.

If you must use a function, pass on the string_01 directly, I think it will be something like a "const char PROGMEM *" or a "PSTR" as parameter.

Ahh,yes, that was the problem.
Well, all sample code I saw used a 2 dimension char table to store the strings, and my sendProgMemStrings function expected also that, but I used only a simple array…

Here is a very well working example: