HTTP client - what is the difference between these 2 calls?

hi,

I'm checking about 40 analog sensors - if a LED is on or off the photoresistor reacts and I want to update that status by doing a http request.

This call is working:

    if (index == 0) { client.print("GET /rover.asp?action=devE6off HTTP/1.0\r\n\r\n");}
    if (index == 1) { client.print("GET /rover.asp?action=devE6on HTTP/1.0\r\n\r\n");}
    if (index == 2) { client.print("GET /rover.asp?action=devB6off HTTP/1.0\r\n\r\n");}
    ...

as that is inefficient I wanted to have the action in an array and construct the call using string operations - I have the array of strings like this:

char* ActionStr[]= {"devE6off",   "devE6on",     //  0,  1
                    "devB6off",   "devB6on",     //  2,  3
                    "devC1off",   "devC1on",     //  4,  5
                    ...

and I construct the call like this:

String suf = " HTTP/1.0\r\n\r\n";
String pref = "GET /rover.asp?action=";

Request = pref + ActionStr[index] + suf;
Serial.println("");
Serial.print(Request);
client.print(Request);

I can't understand why on the serial monitor the call looks exactly like it's supposed to look. When it does the request it works fine on the hardcoded string between quotes but not when it's a concatenated string - even if that one prints fine on the serial.print monitor ?

The log from the webserver gives below result which indicates that something is not so ok:

6-2-2013 22:17:57  - Web Server -  Got data but was not PUT or GET, from: 192.168.2.189 Data:  HTTP/1.0
6-2-2013 22:17:57  - Web Server -  Got data but was not PUT or GET, from: 192.168.2.189 Data: devD1off HTTP/1.0
6-2-2013 22:17:56  - Web Server -  Got data but was not PUT or GET, from: 192.168.2.189 Data: tion=devC3on HTTP/1.0
6-2-2013 22:17:56  - Web Server -  Got data but was not PUT or GET, from: 192.168.2.189 Data: ff HTTP/1.0

One or two calls work in the concatenation method but most fail whereas all work in the hardcoded call. I really would like to understand what is happening - not the end of the world as it works but the string construction saves me quite a bit of memory.

The code for opening the connection and closing is identical in both cases I only changed the client.print for the http request.

Thank you!
Jhh

http://snippets-r-us.com might be able to help you with the snippets. Here, we need to see all of your code. Mixing Strings and strings is not a good idea, though.

hi,

Sketch included - it must be confused about String / char just like I am. I do 2 webcalls - one to set the status, the other one is to call a local Apache so I can see some debug data with some ';' in the log for parsing.

When I sent both calls to the apache webserver it was fine also - so my status server is a bit picky - first line is logging - second sets the status (both in apache log):

first two outlets are indeed off as the analogRead is 0, last one is on as the analogRead is 477 - so that bit works :+)

[07/Feb/2013:19:07:06 +0100] "GET /;Mod-1/Dev11;UIT;0; HTTP/1.0" 404 217
[07/Feb/2013:19:07:06 +0100] "GET /rover.asp?action=devD4off HTTP/1.0" 404 207
[07/Feb/2013:19:07:06 +0100] "GET /;Mod-1/Dev12;UIT;0; HTTP/1.0" 404 217
[07/Feb/2013:19:07:06 +0100] "GET /rover.asp?action=devG3off HTTP/1.0" 404 207
[07/Feb/2013:19:07:06 +0100] "GET /;Mod-2/Dev0;AAN;477; HTTP/1.0" 404 218
[07/Feb/2013:19:07:06 +0100] "GET /rover.asp?action=devB2on HTTP/1.0" 404 207

Could it be an end of char code which I can't see but is sent anyway? strlen says devD4off is 8 long when I tried to find out about \0 but can't 'see' it. If so how can I get rid of this? I know it's a long read so thank you if you got this far! Scan for 'this call does not work' and 'these calls work fine' in the code to see where things go wrong.

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

// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress server(192,168,2,155);
char suf[] = " HTTP/1.0\r\n\r\n";
char pref[] = "GET /rover.asp?action=";
String Log;

int pbIn = 0;                    // Interrupt 0 is on DIGITAL PIN 2!
int ReadIn = 2;                  // Interrupt 0 is on DIGITAL PIN 2!
int ledOut = 22;                 // The output LED pin
int RelEen = 41;                 // Relais 1
int RelTwee = 42;                // Relais 2
volatile int count = 0;          // Counter - add 1 when button pushed else add 0
volatile int hold = LOW;         // Determine how long button was pushed
volatile int flag = LOW;         // Button was pushed 

// Multiplex - module link table
// pin1, pin2, pin3, pin4, pinstate1, pinstate2, pinstate3, pinstate4, cut-off, null, sensor on (1)/off (0)/undetermined (3), analog read pin, module number, outlet number, index in action table
// pin1, pin2, pin3, pin4, pinstate1, pinstate2, pinstate3, pinstate4, low, high, dim value/undetermined (3), analog read pin, module number, outlet number, index in action table
int MultiP[41][15] = {
      { 33, 32, 31, 30, 0, 0, 0, 0, 100,   0, 3, 8, 1,  0,  0}, 
      { 33, 32, 31, 30, 0, 0, 0, 1, 100,   0, 3, 8, 1,  1,  2}, 
      { 33, 32, 31, 30, 0, 0, 1, 0, 100,   0, 3, 8, 1,  2,  4}, 
      { 33, 32, 31, 30, 0, 0, 1, 1, 100,   0, 3, 8, 1,  3,  6}, 
      { 33, 32, 31, 30, 0, 1, 0, 0, 100,   0, 3, 8, 1,  4,  8}, 
      table reduced in size
      { 33, 32, 31, 30, 1, 0, 1, 1, 100,   0, 3,10, 3, 11, 74},
      { 33, 32, 31, 30, 1, 1, 0, 0, 100,   0, 3,10, 3, 12, 76},
      { 33, 32, 31, 30, 0, 0, 0, 0,   5, 950, 3, 1, 9,  1,  0},
      { 22, 22, 41, 42, 0, 0, 0, 0,   0,   0, 0, 0, 0,  0,  0}   // define pin 22, 41, 42 as output
    };

char* ActionStr[]= {"devE6off",   "devE6on",     //  0,  1
                    "devB6off",   "devB6on",     //  2,  3
                    "devC1off",   "devC1on",     //  4,  5
                    "devD7off",   "devD7on",     //  6,  7
                    table reduced in size...
                    "eventDummy", "eventDummy",  // 72, 73
                    "devF2off", "devF2on",       // 74, 75
                    "devD6off", "devD6on"        // 76, 77
 };


// Number of sensors to be monitored 
int NikoCount = 40;  

// Initialize the Ethernet client library
EthernetClient client;

void setup() {

// Open serial communications
  Serial.begin(9600);
  
// Set pinMode for mulitplexer address pins and others (this is the +1)
  for (int thisPin = 0; thisPin < (NikoCount + 1); thisPin++)  {
      pinMode(MultiP[thisPin][0], OUTPUT);      
      pinMode(MultiP[thisPin][1], OUTPUT);
      pinMode(MultiP[thisPin][2], OUTPUT);
      pinMode(MultiP[thisPin][3], OUTPUT);
  }

// Status light off, Relais both open
  digitalWrite(ledOut, LOW);
  digitalWrite(RelEen, HIGH);
  digitalWrite(RelTwee, HIGH);

// Attach the interrupt to the input pin and monitor for ANY Change
  attachInterrupt(pbIn, stateChange, CHANGE);
  
// Start the Ethernet connection:
  Serial.println("Init ethernet...");
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    while (true){
       digitalWrite(ledOut, HIGH); delay(500);
       digitalWrite(ledOut, LOW);  delay(300);
    }
  }
  // give the Ethernet shield a second to initialize:
  Serial.println("Init ethernet ok.");
  delay(1000);
  Serial.println("Connecting...");
}

void loop()
{
  String a;
  int dimRange;
  int sensorValue;
  int sensorValueRaw;

  for (int ctr = 0; ctr < NikoCount; ctr++)  {
    
// First check if there is anything to be handled from the interrupt
//
   code taken out...
   
// Set address on analog multiplex chip
   digitalWrite(MultiP[ctr][0], MultiP[ctr][4]);
   digitalWrite(MultiP[ctr][1], MultiP[ctr][5]);
   digitalWrite(MultiP[ctr][2], MultiP[ctr][6]);
   digitalWrite(MultiP[ctr][3], MultiP[ctr][7]);
// wait for chip to settle
   delay(50);
// Read analog value   
   sensorValue = analogRead(MultiP[ctr][11]);
   if (MultiP[ctr][12] == 9){
//   Module 9 is to measure dimmers - low and high should be capped
//   and the sensor reading converted to a percentage
     code taken out....
   }
   else {
// If analog reading below cut-off then led is not on check against remembered status in MultiP[..][10]
// and toggle if required
   if (sensorValue < MultiP[ctr][8]) {
     if (MultiP[ctr][10] != 0) {
       MultiP[ctr][10] = 0;
       digitalWrite(ledOut, HIGH);
       delay(30);
       digitalWrite(ledOut, LOW);
       Log = ";Mod-" + String(MultiP[ctr][12]) + "/Dev" + String(MultiP[ctr][13]) + ";UIT;" + String(sensorValue) + ";";
       a = connectAndReadLog(Log);
       a = connectAndRead(MultiP[ctr][13],0,MultiP[ctr][12],MultiP[ctr][14]);
       Serial.println(a);
       }
   }
   else {
// If analog reading below cut-off then led is not on check against remembered status in MultiP[..][10]
// and toggle if required
     if (MultiP[ctr][10] != 1) {
       MultiP[ctr][10] = 1;
       digitalWrite(ledOut, HIGH);
       delay(30);
       digitalWrite(ledOut, LOW);
       Log = ";Mod-" + String(MultiP[ctr][12]) + "/Dev" + String(MultiP[ctr][13]) + ";AAN;" + String(sensorValue) + ";";
       a = connectAndReadLog(Log);
       a = connectAndRead(MultiP[ctr][13],1,MultiP[ctr][12],MultiP[ctr][14]);
       Serial.println(a);
     }
    }
   }
 } // NikoCount loop
}  // Void loop


String connectAndRead(int line, int col, int sensor, int Req){

  int index;
  // if you get a connection, report back via serial:
  if (client.connect(server, 81)) {
    //Serial.println("connected");
    // Make a HTTP request:
    if (sensor == 9) {
         code taken out
    }
    else
    {
    // "GET /rover.asp?action=" + action[index] + " HTTP/1.0\r\n\r\n";
    index = Req + col;
    Serial.println("");
    Serial.print(pref);
    Serial.print(ActionStr[index]);
    Serial.print(suf);
    // this call does not work - concatenating prefix + variable action part + suffix
    client.print(pref);
    client.print(ActionStr[index]);
    client.print(suf);
    }
    /*
    // these calls works fine:
    if (index == 0) { client.print("GET /rover.asp?action=devE6off HTTP/1.0\r\n\r\n");}
    if (index == 1) { client.print("GET /rover.asp?action=devE6on HTTP/1.0\r\n\r\n");}
    if (index == 2) { client.print("GET /rover.asp?action=devB6off HTTP/1.0\r\n\r\n");}
    left out quite a few here...
    if (index == 75) { client.print("GET /rover.asp?action=devF2on HTTP/1.0\r\n\r\n");}
    if (index == 76) { client.print("GET /rover.asp?action=devD6off HTTP/1.0\r\n\r\n");}
    if (index == 77) { client.print("GET /rover.asp?action=devD6on HTTP/1.0\r\n\r\n");}
    */
  }
    client.stop();
  return "OK";
}

String connectAndReadLog(String log){
  // if you get a connection, report back via serial:
  if (client.connect(server, 80)) {
   client.print("GET /" + log + " HTTP/1.0\r\n\r\n");
  }
  client.stop();
  return "OK";
}


void stateChange()
{
  hold = digitalRead(ReadIn);
  count = digitalRead(ReadIn);
  if (digitalRead(ReadIn) == HIGH) {
    flag = HIGH;
  }
  digitalWrite(ledOut, digitalRead(ReadIn)); 
}

Please note that, at present, the String library has bugs as discussed here and here.

In particular, the dynamic memory allocation used by the String class may fail and cause random crashes.

I recommend reworking your code to manage without String. Use C-style strings instead (strcpy, strcat, strcmp, etc.).

Alternatively, install the fix described here:
http://arduino.cc/forum/index.php/topic,145765

int MultiP[41][15] = {

How many bytes is this? 615 ints at two bytes each is using 1,230 bytes of the 2048 that you have. All of your other variables, including serial buffers, stuff used by the Ethernet, SPI, and String classes (as well as the String instance) plus the constant strings in your code, as well as the function stack need to fit in the remaining 818 bytes. I'm guessing that that is a really tight fit. PROGMEM for that array might help. Ditching the String class will definitely help. Using the F() macro around constant strings in print() method calls wouldn't hurt.

I'm guessing that that is a really tight fit. PROGMEM for that array might help. Ditching the String class will definitely help. Using the F() macro around constant strings in print() method calls wouldn't hurt.

You're absolutely right it is a close call - my sketch is using about 22000 of 258048 bytes and I'm running into memory problems. So I have been reading on 'Types of memory available on an Arduino' and now I begin to understand why. For sure the calls to the status server are fixed enough to be in that progmem.

Thanks!

You're absolutely right it is a close call - my sketch is using about 22000 of 258048 bytes and I'm running into memory problems.

This is the first indication that you are using a Mega. With 8K of memory, it doesn't look you should be having memory issues.

This is the first indication that you are using a Mega. With 8K of memory, it doesn't look you should be having memory issues

I'm using pins 41 and 42 to trigger a relais and analog pins 8, 9, 10 to read sensor values - ok those hints towards a Mega are carefully hidden in my array int MultiP[41][15] so I'm guilty of asking a clumsy question.

The fact that I cannot concatenate http prefix + action + suffix in a sensible call is the question I'm struggling with. I didn't realize I was mixing up variable types String and char.

The knowledge that 49 chars for a single http call times 70 can be stored somewhere more sensible is not what I asked but it is helpful. So even if I don't manage to do my string concatenation I can work around that by storing the strings in different memory. I ran into cases where my sketch wouldn't do anything unless I reduced it in size which I ended up doing - next step in reducing size was to concatenate the http call and then I got stuck.

Thanks!