substring returns nothing

I started working on a light switch, and want it to be controlled through my wishield 2.0, but I got some problems with getting stuff out of the url.

When i call http://192.168.1.10/?on=20000000, it converts the char* into a string, and detects that there are “?on=” in the url, so far so good.

I then want what is comming after the = because that is the time it should be on before shutting off again, but it just returns nothing.

As it is right now, it is just using this “WiServer.print(temp.substring(1, 5));” just to check if it is working, and that returns nothing too… That should actually return “on=20”?

The readout of “temp” right after the string is build is right, as it tells me it is “/?on=20000000”

What is going on here? :-?

#include <WiServer.h>
#define WIRELESS_MODE_INFRA      1
#define WIRELESS_MODE_ADHOC      2

#include <WString.h>                // include the String library

boolean debug = true;

// Wireless configuration parameters ----------------------------------------
unsigned char local_ip[] = {192,168,1,10};      // IP address of WiShield
unsigned char gateway_ip[] = {192,168,1,1};      // router or gateway IP address
unsigned char subnet_mask[] = {255,255,255,0};      // subnet mask for the local network
const prog_char ssid[] PROGMEM = {"dd-wrt"};            // max 32 bytes

unsigned char security_type = 3;      // 0 - open; 1 - WEP; 2 - WPA; 3 - WPA2

// WPA/WPA2 passphrase
const prog_char security_passphrase[] PROGMEM = {"xxxxxxxxxxx"};      // max 64 characters

// WEP 128-bit keys
// sample HEX keys
prog_uchar wep_keys[] PROGMEM = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,      // Key 0
                          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,      // Key 1
                          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,      // Key 2
                          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00      // Key 3
                        };

// setup the wireless mode
// infrastructure - connect to AP
// adhoc - connect to another WiFi device
unsigned char wireless_mode = WIRELESS_MODE_INFRA;

unsigned char ssid_len;
unsigned char security_passphrase_len;
// End of wireless configuration parameters ----------------------------------------

// This is our page serving function that generates web pages
boolean sendMyPage(char* URL)
{
  String temp = "";
  
  for (int i=0; i < 60; i++)
  {
    temp.append(URL[i]);
  }
  
  if (debug) Serial.println(temp);
    
  if(temp.contains("?on="))
  {    
    WiServer.print("Turned on for ");
    WiServer.print(temp.substring(1, 5));
    
    if (debug) Serial.println(temp.substring(temp.indexOf("="), temp.length()));
    return true;
  }
  
  else if (strcmp(URL, "/") == 0)
  {
    // Use WiServer's print and println functions to write out the page content
    WiServer.print(analogRead(0));
    return true;
  }
  
  else
  {
    WiServer.print("COMMAND NOT FOUND");
    return true;
  }
  return false;
}

void setup()
{
  Serial.begin(9600);
  Serial.println("Serial Ready");
  
  // Initialize WiServer and have it use the sendMyPage function to serve pages
  WiServer.init(sendMyPage);
}

void loop()
{
  // Run WiServer
  WiServer.server_task();
}

This code has a problem:

temp.substring(temp.indexOf("="), temp.length())

temp.length() returns the number of characters in the array. The index of the last character, then, is temp.length()-1.

You have access to the source code for the string class. Why not add debug statements (Serial.print and/or Serial.println) to the methods in the class, to figure out what is going on?

One thing I notice is that String::substring returns a new String object. But that object goes out of scope when the function ends, which should trigger the destructor, which frees the memory being used by that object. You might want to add a Serial.print to the destructor to see if it is indeed being called before you get to use the returned string.

Okay, I just did... apparently nothing goes on... or, a lot actually... but haven't been able to find where the input actually is... all I find, is empty readouts...

And I don't see why there actually should be anything wrong with the function itself, I see others use it the same way I do... except mine doesn't return anything.

Just tried to take a copy of another project i found: http://blog.richard.parker.name/2009/04/25/how-to-build-a-web-connected-gas-meter-with-your-arduino/

Line 93

if (url.contains("x") && unlock) {
            Serial.println(url);
            String v = String(10);
            int startIndex = url.indexOf('=')+1;
            int stopIndex = url.indexOf('H');
            v = url.substring(startIndex, stopIndex);
            Serial.println(v);
            totalTicks = atoi(v);
          }

Changed it into

String temp = "";
  temp += "/?on=20000000";
  if (debug) Serial.print("Output: ");
  
  String v = String(10);
  v = temp.substring(0, 10);
  
  if (debug) Serial.println(v);

So it should give me from 0 to 10, but no output.

I downloaded the string library, for 0017, and added a bunch of Serial.print statements to it. One of the constructors looks like this:

String::String(const char* bytes)
{
  if(bytes == NULL)
    bytes= "";
  _length = strlen(bytes);

  //if (_capacity < _length) {
  _capacity = _length;
  //  free(_array);
  _array = (char*)malloc(_length+1);
  //}
     
  clear();  
  setArray(bytes);
}

The clear() function sets _length to 0. The setArray function then copies _length bytes into the array that serves as the string storage. Well, obviously, that’s a problem. The substring function also relies on _length being set properly.

I added

  _length = strlen(bytes);

after the call to clear. Now, the rest of my sketch works correctly.

#include "WString.h"

void setup()
{
  Serial.begin(9600);
  String temp("/?on=200000000");
  
  int tempLen = temp.length();
  Serial.print("temp length: ");
  Serial.println(tempLen);

  Serial.print("temp = [");
  Serial.print(temp);  Serial.print("]\n");
  
  String on = temp.substring(1,5);
  Serial.print("on = [");
  Serial.print(on);  Serial.print("]\n");
}

void loop()
{
}

This prints

temp length: 14
temp = [/?on=200000000]
on = [?on=]

Great! Got it working too, and learned something more about how do make classes and such. :)

Looked over the other projects again, no one of them say anything of changes needed to be done.

There are other places where clear() is called after _length is set - the copy constructor and both = operators.

The method of creating a string given the length, and appending data (using append or +=) to the (empty) string seems to work.