Uno + Ethernet Shield to PHP

Pay close attention to how my code reads the response from the server and closes the connection. The server will close the connection when it is finished sending packets, then you close your end.

It is basically this client code in the playground. http://www.arduino.cc/playground/Code/WebClient

so I changed the last two delays to 1ms to fake the data stream, it hangs on pass 25 waits a bit then continues. is this a logical stress test?

*Edit: second hang on pass 302

I can't be sure if this is because of Ethernet Shield or Arduino Uno? Which ones buffer full's up?

Using Arduino Mega by having more processor power and flash memory should solve this out?

KodiakBear: so I changed the last two delays to 1ms to fake the data stream, it hangs on pass 25 waits a bit then continues. is this a logical stress test?

*Edit: second hang on pass 302

Are you talking about my code or yours? If mine, which two delays did you change? What does the serial monitor say about that connection hang? If it is "Timeout", that takes 10 seconds before the connection will timeout and resume. That normally happens when there is a connection break, like pulling the CAT5 cable connector out of the ethernet shield or powering cycling the router.

The ethernet shield does the buffering. If the tx buffer fills up, the write function is blocking (waits for tx buffer space before returning).

yes I am talking about your code. there are three delays in your code first one is for ethernet shield to initialize. the rest is like this ;

if(loopCount < 30)
  {
    delay(1);
  }
    delay(1);
    connectLoop++;
    if(connectLoop > 10)

I changed these delays to 1

I don't have a router, I have a cat5 cable to my mac directly, mac is the localhost. so there is no router.

Serial monitor only says connecting... if it hangs. from that second hang on 302 it is still streaming data and it is around pass 3300 between 302 and 3300 there was no hang. which is so weird.

it hangs for 302 post and doesn't hang for 3000 posts..

The first change is ok. The second is not. The server may not respond in 10 ms. You can change the delay to 1 ms, but you must wait at least a couple seconds before timing out. Like this is ten seconds:

    delay(1);
    connectLoop++;
    // if no packet for 10000 milliseconds
    if(connectLoop > 10000)

edit: Are you using Apache in your Mac? If so, what does the log say?

Maybe I wasn't clear about the timeout. That would only happen if the server does not either send another packet, or close the connection. Most of the time, the server response and close should be immediate. Then you would not wait nearly 10 seconds.

Yes I am using Mac with MAMP which is Apache..

I used the last code you sent there was no hang. then I switched back to 10ms there was no hang too..

We are also working with pc's installed WAMP, also testing there..

I believe sometimes when it starts to stream if it doesn't hang, it doesn't hang ever in that session. If I close the serial then open it back for a new session it may hang.. we have been testing this for 4 days :/

and I don't know how to look up to apache log.

KodiakBear: and I don't know how to look up to apache log.

I suggest you find out about the logs. Every time your Arduino makes that request, it should be putting an entry in the log. At your request rate, the logs can get quite large in a very short time. And Apache saves four weeks of logs.

The timeout should be left alone. When you are connected directly to the Mac, this may not be a problem. But when you put a router with a computer and an internet connection into the network, things change. But that is up to you. You can test it, and if it performs ok, use it! :)

okay I will take a look at the logs now.

whole project will be working in a local area network. there won't be any router or internet connection in any time of this project scope.

SurferTim,

Big fan of yours because of your ethernet bug solution for v1.0 IDE :)

I am working on the same project with KodiakBear.

I wrote the following code simultaneously with him. Mine is working well. The following code is working on my computer(Windows 7) without stalling. I 've tried it on 2 different XP computers and it does not stall on them as well. But we are not sure it will not stall somewhere, sometime.

#include 
#include 
#include 
byte mac[] = {  0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 };
char serverName[] = "192.168.1.12";
EthernetClient client;
TextFinder finder( client );

void setup() 
{
       // Open serial communications and wait for port to open:
        pinMode(4,OUTPUT);
        digitalWrite(4,HIGH);
        Serial.begin(9600);
        while (!Serial) 
         {;} // wait for serial port to connect. Needed for Leonardo only


  // start the Ethernet connection:
        if (Ethernet.begin(mac) == 0) 
        {
          Serial.println("Failed to configure Ethernet using DHCP");
          // no point in carrying on, so do nothing forevermore:
          while(true);
        }
  // give the Ethernet shield a second to initialize:
        delay(1000);
        Serial.println("connecting...");

                    // if you get a connection, report back via serial:
                    
                            if (client.connect(serverName, 80)) 
                            {
                              Serial.println("connected");
                              // Make a HTTP request:
                          //    client.println("GET /data.php");
                              client.write("GET /data.php HTTP/1.0\r\n\r\n");
                            
                            } 
                            else 
                            {
                              // kf you didn't get a connection to the server:
                              Serial.println("connection failed");
                            }
}     //END OF SETUP

void loop()
{
  // if there are incoming bytes available 
  // from the server, read them and print them:
  if (client.available()) 
  {
    Serial.println("Client available");
    
    //begin get user count
    finder.find("#"); //get user count
    long user_count = finder.getValue();
    Serial.print("User Count:");
    Serial.print(user_count); 
    Serial.println("");
    //end get user count
    //begin get car choice
    finder.find("[");
    long car_type = finder.getValue(); 
    Serial.print("Car Type:");
    Serial.print(car_type); 
    Serial.println("");
    // end get car choice
    // begin get first user speed
    finder.find("<");
    long speed_1 = finder.getValue(); 
    Serial.print("Speed 1:");
    Serial.print(speed_1); // end get first user speed
    Serial.println("");
    // end get first user speed
    // begin get second user speed
    finder.find("{");
    long speed_2 = finder.getValue(); 
    Serial.print("Speed 2:");
    Serial.print(speed_2); 
    Serial.println("");
    // end get second user speed
    client.stop();
    //client.flush();
   
/*    int motor1_hiz = speed_1/4;
    digitalWrite(motor1_input_1, HIGH);
    digitalWrite(motor1_input_2, LOW);
    analogWrite(motor1_en,motor1_hiz);    
    
    int motor2_hiz = speed_2/4;
    digitalWrite(motor2_input_1, HIGH);
    digitalWrite(motor2_input_2, LOW);
    analogWrite(motor2_en,motor2_hiz); */
    }
    delay(100);

  
/*   if (!client.connected()) 
   {
    Serial.println("Client is not connected");
    client.stop();
   }*/

//This is your hack from couple months ago 
/*int newFree = client.free();

if(newFree < 1000)
{
   Serial.print("Low buffer ");
   Serial.println(newFree, DEC);
}   */
   
 if (client == false) // there was a bunch of code between the following and client.stop. So I wrote this. Now it is not necessary for now
 {
      
    if(client.connect(serverName, 80))
   { 
   //   client.println("GET /data.php"); 
      client.write("GET /data.php HTTP/1.0\r\n\r\n"); 
    //  client.write();
   //   client.println();
   }
 }  
    
} // END OF CODE

Here is the serial print:

connecting...
connected
Client available
User Count:2
Car Type:1
Speed 1:706
Speed 2:470
Client available
User Count:2
Car Type:1
Speed 1:706
Speed 2:470
.
.
.

So, is it possible for you to compare two different codes and figure out what the problem might be? I think I go around the problem somewhere.

Edit: added last sentence, my bad.

@cer: Thanks! It is now included in IDE v1.0.1. :)

I use my code. I have already debugged it and put it in the playground. http://www.arduino.cc/playground/Code/WebClient It has a good connection fail timeout and response display. It should keep running no matter what happens. If it doesn't, the serial monitor should be helpful in troubleshooting. I have intentionally failed the connection during a download to test it. It recovers fine.

@cer: Thanks! It is now included in IDE v1.0.1.

Yeah, I saw that :) I gave you the king's crown in my mind :)

I use my code. I have already debugged it and put it in the playground.

I 'm now trying it. I'll share the results.

Thank you.

If you are trying the same type code, then I recommend reducing the time between requests slowly. Try it at 10 seconds apart to start instead of 30 seconds. That is fast enough to test, but slow enough so you can read the serial monitor. Once that is working, then slowly reduce the time between requests.

so I have been inspecting apache logs in realtime over mac os x terminal.

it is clear that when arduino hangs on GET, Apache simply waits for GET request. There is nothing seems to be wrong in the server side.

if I change my slider in the browser when hang happens, it does send the slider value to sql according to apache logs

KodiakBear: so I have been inspecting apache logs in realtime over mac os x terminal.

it is clear that when arduino hangs on GET, Apache simply waits for GET request. There is nothing seems to be wrong in the server side.

if I change my slider in the browser when hang happens, it does send the slider value to sql according to apache logs

Slider?

How often are you sending requests now? Are you still waiting the one millisecond between requests?

@SurferTim,

This is modified version of your code(http://www.arduino.cc/playground/Code/WebClient)

It works like a charm but I am still not sure if it is still stable. I mean your part of code is great, but what I did might be changed the stability.

What do you think?

/* Web client sketch for IDE v1.0.1 and w5100/w5200 Posted October 2012 by SurferTim */

include

include

include

byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 }; //IPAddress ip(192,168,1,12); //IPAddress gateway(192, 168, 1, 12); //IPAddress subnet(255, 255, 255, 0);

IPAddress server(192,168,1,12); // Google EthernetClient client;

int totalCount = 0; int loopCount = 0; char pageAdd[32]; TextFinder finder( client ); void setup() { Serial.begin(9600);

pinMode(4,OUTPUT); digitalWrite(4,HIGH);

Ethernet.begin(mac); delay(2000); Serial.println("Ready"); }

void loop() { if(loopCount < 10) { delay(10); } else { loopCount = 0; sprintf(pageAdd,"/data.php",totalCount); if(!getPage(server,pageAdd)) Serial.print("Fail "); else Serial.print("Pass "); totalCount++; Serial.println(totalCount,DEC); }

loopCount++; }

byte getPage(IPAddress ipBuf,char *page) { int inChar; char outBuf[128];

Serial.print("connecting...");

if(client.connect(ipBuf,80)) { Serial.println("connected");

sprintf(outBuf,"GET %s HTTP/1.0\r\n\r\n",page); client.write(outBuf); } else { Serial.println("failed"); return 0; }

int connectLoop = 0;

while(client.connected()) { while(client.available()) { // inChar = client.read(); // Serial.write(inChar); finder.find("<"); long speed_1 = finder.getValue(); Serial.print("Speed 1:"); Serial.print(speed_1); // end get first user speed Serial.println("");

client.flush(); client.stop(); /* finder.find("<"); long speed_1 = finder.getValue(); Serial.print("Speed 1:"); Serial.print(speed_1); // end get first user speed Serial.println("");/ connectLoop = 0; } / if (client.available()) { // char c = client.read(); // Serial.print(c); // Serial.println("b");

finder.find("<"); // seek to the Results field long value = finder.getValue(); // get numeric value Serial.print(value); Serial.println(""); client.flush(); client.stop(); }/ connectLoop++; if(connectLoop > 10000) { **Serial.println(); **Serial*.println("Timeout"); client.stop(); } delay(1); }

Serial.println();

Serial.println("disconnecting."); client.stop();

return 1; }

What does this connectLoop do by the way? It is just for testing i suppose, right?

connectLoop++;
    if(connectLoop > 100)
    {
      Serial.println();
      Serial.println("Timeout");
      client.stop();
    }

...and here is the serial print:

Pass 1431
connecting...connected
Speed 1:706

disconnecting.
Pass 1432
connecting...connected
Speed 1:706

disconnecting.
Pass 1433
connecting...connected
Speed 1:706

disconnecting.
Pass 1434
connecting...connected
Speed 1:706

disconnecting.
Pass 1435
connecting...connected
Speed 1:706

disconnecting.

Thank you in advance

The variable connectLoop controls the timeout. If the connection breaks, like hardware fail, it prevents the "while(client.connected()" loop from becoming an endless loop. I tested that by downloading a big webpage and pulling the CAT5 connector out of the shield halfway through the download. Then a couple minutes later, after several failed connection attempts, I plugged it back in, and it went right back to working.

edit: The "while(client.connected())" loop is exited when the server sends a close message, but not a hardware fail. If the connection breaks, the close message never gets through to the client from the server, and the client code hangs in that loop.

The connectLoop counts the iterations of that loop with no packet received. With the delay(1) in the loop, it is about a millisecond through each iteration, so I used 10000 as the number of times through the loop without a packet to exit the loop with the "client.stop()" call (no packet for 10 seconds). The other comparison loops exit normally, and the last client.stop() does nothing but return if the connection is closed.

@SurferTim

I got it. You thought of everything :) That's great, you saved my day, thank you very much!

I have a project to control 2 servos using button on php web. I've tried to connect the arduino to PHP then serial monitor shows this:

Starting ethernet...
192.168.0.4
Ready
connecting...connected
HTTP/1.1 200 OK
Date: Thu, 04 Jul 2013 08:47:15 GMT
Server: Apache/2.2.11 (Win32) DAV/2 mod_ssl/2.2.11 OpenSSL/0.9.8i mod_autoindex_color PHP/5.2.8
Content-Length: 1404
Connection: close
Content-Type: text/html;charset=utf-8



 
  Index of /
 
 

Index of /

Icon  Name                    Last modified      Size  Description
[DIR] Dessy/                  04-Jul-2013 14:26    -  [DIR] Image/                  01-Jul-2013 13:35    -  [DIR] TA/                    15-Jun-2013 07:31    -  [DIR] bacup/                  21-Dec-2007 09:01    -  [DIR] gagal/                  14-Jun-2013 20:58    -  [DIR] includes/              01-Jul-2013 13:37    -  [DIR] jadi/                  03-Jul-2013 22:00    -  [DIR] xampp/                  21-Dec-2007 09:01    - 
Apache/2.2.11 (Win32) DAV/2 mod_ssl/2.2.11 OpenSSL/0.9.8i mod_autoindex_color PHP/5.2.8 Server at 192.168.0.2 Port 80
disconnecting. Pass 1

Is the information above shows that the arduino and php are connected? If yes, I don't know how to control the servos using button on php web. Help me please