Go Down

Topic: Ethernet Shield V3 - still freezing (4 sockets limit? client.stop() problem?) (Read 1 time) previous topic - next topic

kev8

Hello, I'm new here (sorry, I didn't present myself yet.. maybe later..).

Setup:
Arduino UNO v.3 (IDE 1.0.3) + Ethenet Shield v.3 - [programmed as simple client that reads a txt file on a webserver]

Problem:
It's 2012 2013  :)  and I still see my shield (programmed as client) functioning well but then freezing after some time while reading a txt file from a web server (GET method).
It seems that it is related to the 4 sockets limit and the client.stop() function not working, so that sockets are not closed poperly.

I tried to follow all the several methods described in the forum, but they did not seem to work:
- disable SD pin 4 (HIGH)
- delays everywhere
- flushing everywhere
- checking client.connected();
- checking client.status();
- relaunching Ethernet.begin(mac) ..

These are old 2009-2011 advices, some of them are outdated or already included in the Libraries (SurferTim patch, ...).

So my question(s):
What is the state or the art? Is the shield working for you?
Is the client.stop() - socket disconnession solved or still an issue?

Thanks to all. Maybe I'll post the code also..

SurferTim

Quote
So my question(s):
What is the state or the art? Is the shield working for you?
Is the client.stop() - socket disconnession solved or still an issue?

Thanks to all. Maybe I'll post the code also..

I think the w5200 is the state of the art, but not widely available yet.
The ethernet shield is working good for me.
The socket disconnect is not an issue with my code.

Post your code. Here is mine:
http://playground.arduino.cc/Code/WebClient

zoomkat

As a server I set the refresh rate in the below code to 0 and let it run with IE requesting the updates. It made 500,000+ refreshes without hanging, so the serving side is stable with simple code.

Code: [Select]

// zoomkat's meta refresh data iframe test page 12/24/12
// use http://192.168.1.102:84 in your brouser for main page
// http://192.168.1.102:84/data static data page
// http://192.168.1.102:84/datastart meta refresh data page
// for use with W5100 based ethernet shields
// set the refresh rate to 0 for fastest update
// use STOP for single data updates

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

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
byte ip[] = { 192, 168, 1, 102 }; // arduino 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
unsigned long int x=0; //set refresh counter to 0
String readString;

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

void setup(){
  Serial.begin(9600);
  Ethernet.begin(mac, ip, gateway, gateway, subnet);
  server.begin();
  Serial.println("meta refresh data frame test"); // so I can keep track of what is loaded
}

void loop(){
  EthernetClient client = server.available();
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
         if (readString.length() < 100) {
          readString += c;
         }
        //check if HTTP request has ended
        if (c == '\n') {

          //check get atring received
          Serial.println(readString);

          //output HTML data header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();

          //generate data page
          if(readString.indexOf("data") >0) {  //checks for "data" page
            x=x+1; //page upload counter
            client.print("<HTML><HEAD>");
            //meta-refresh page every 1 seconds if "datastart" page
            if(readString.indexOf("datastart") >0) client.print("<meta http-equiv='refresh' content='0'>");
            client.print("<title>Zoomkat's meta-refresh test</title></head><BODY><br>");
            client.print("page refresh number ");
            client.print(x); //current refresh count
            client.print("<br><br>");
              //output the value of each analog input pin
             for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
             client.print("analog input ");
             client.print(analogChannel);
             client.print(" is ");
             client.print(analogRead(analogChannel));
             client.print("<br>");
             }
            client.print("</BODY></HTML>");
           }
          //generate main page with iframe
          else
          {
            client.print("<HTML><HEAD><TITLE>Zoomkat's frame refresh test</TITLE></HEAD>");
            client.print("Zoomkat's Arduino frame meta refresh test 12/24/12");
            client.print("<BR><BR>Arduino analog input data frame:<BR>");
            client.print("&nbsp;&nbsp;&nbsp;&nbsp;<a href='http://192.168.1.102:84/datastart' target='DataBox' title=''yy''>REFRESH</a>");
            client.print("&nbsp;&nbsp;&nbsp;&nbsp;<a href='http://192.168.1.102:84/data' target='DataBox' title=''xx''>STOP</a><BR>");
            client.print("<iframe src='http://192.168.1.102:84/data' width='35%' height='250' name='DataBox'>");
            client.print("</iframe><BR></HTML>");
          }
          delay(1);
          //stopping client
          client.stop();
          //clearing string for next read
          readString="";
        }
      }
    }
  }
}

Google forum search: Use Google Advanced Search and use Http://forum.arduino.cc/index in the "site or domain:" box.

kev8

Just a quick update:
Many thanks for your examples. I'm using them to debug more and trying new things.
My general impression for now is that the shields functions, but freezes often when reading data (a text file) from the server (client.read()).
I'll post more later.. bye!

SurferTim

Quote
My general impression for now is that the shields functions, but freezes often when reading data (a text file) from the server (client.read()).

Mine functions great and doesn't freeze. Sounds like zoomkat's doesn't freeze either. Must be your code.


Nick Gammon

Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics


Just a quick update:
Many thanks for your examples. I'm using them to debug more and trying new things.
My general impression for now is that the shields functions, but freezes often when reading data (a text file) from the server (client.read()).
I'll post more later.. bye!

Are you sure the webserver is always available when Arduino tries to read that file? Somebody here on the forum wrote that the method "connect" of the "EthernetClient" class contains a loop of 10 seconds to retry connecting. If the webserver doesn't respond, Arduino hangs. That guy solved the issue by making Arduino act like a server. It waits for a command from the webserver and only then it connects to the webserver (this way Arduino knows the webserver is online).
http://www.ciproconsulting.it

SurferTim

Quote
If the webserver doesn't respond, Arduino hangs.

No, the Arduino waits for the server to respond. It tries 5 times to establish the connection, then returns false if no connection could be established. You can shorten that time by editing the ethernet library files and setting the retry value to less than 5. This is part of the fault tolerance built into the internet.

You can't force it to make a connection that cannot be established. You can only wait a shorter period to determine it failed.

kev8

This is the code, sorry it's not very elegant and can be shortened a lot.

Basically, I took the code from http://arduino.cc/en/Tutorial/WebClientRepeating.
Then I perform 2 GET:
1. the first send sensors reading
2. the second reads a TXT file containing 2 values for switching on/off 2 leds. I took the method here http://bildr.org/?s=client and improved the readPage() function with SurferTim code.
TXT file is a string like <01> (= 4 chars). Each number represents the LED status (0 or 1).
The < and > are used to locate and extract the values, because the answer from server is about 120 chars (contains also headers).

Code: [Select]
// ---------------- IMPORT ------------------------------------
#include <SPI.h>
#include <Ethernet.h>

// ----------------- VARIABLES DEFINITIONS --------------------
byte mac[] = {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

// variables used by millis
unsigned long lastConnectionTime = 0;          // last time you connected to the server, in milliseconds
boolean lastConnected = false;                 // state of the connection last time through the main loop
const unsigned long postingInterval = 10*1000;   // time to wait before repeating connections

// variables for connection
char serverName[] = "myserver.example.org";
EthernetClient client;


// GET #2
String readValue = "";   // String to store the readPage() function result

// variables for sensors
const int tempPin = A0;   // pin where temp sensors is connected
const int lightPin = A1;   // pin where light sensor (photoresistor) is connected
const int ledPinR = 6;   // pin of RED led (LED 1)
const int ledPinW = 2;   // pinf of WHITE led (LED 2)

int tempRead = 0;                              // value read by temperature sensor (0-1023)
float voltage = 0.0;   // voltage of the temp sensor
float temp = 0.0;   // calculated value of the temperature (degrees °C)
int light = 0;   // value read by light sensor
int LED1 = 0;   // value to assign to LED 1
int LED2 = 0;   // value to assign to LED 2



// -----------------SETUP --------------------------------------------
void setup() {
// Open serial communications and wait for port to open:
 Serial.begin(9600);
 
 pinMode (4, OUTPUT);                  //disable SD card slot on ethernet shield
 digitalWrite (4, HIGH);
 pinMode (10, OUTPUT);                  //explicity enable ethernet
 digitalWrite (10, LOW);
 
 // 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:
   for(;;)
     ;}

 // give the Ethernet shield 1 seconds to initialize, then write debug info:
 delay(1000);
 Serial.print("Ethernet begins.. ");
 Serial.println(Ethernet.localIP());
 
 // initializes LEDs
 pinMode(ledPinR, OUTPUT);
 pinMode(ledPinW, OUTPUT);
 digitalWrite(ledPinR, LOW);
 digitalWrite(ledPinW, LOW);
}

// -----------------------------LOOP---------------------
void loop() {

// HTTP REQUEST  
 if(!client.connected() && (millis() - lastConnectionTime > postingInterval)) {

 // Read and calculate temp
     tempRead = analogRead(tempPin);
     voltage = (tempRead/1024.0) * 5.0;
     temp = ((voltage - 0.5) * 100.0);
 // Read Light
     light = analogRead(lightPin);
     
// -------------------------- GET #1 -----------------------------------------------------
// --------------------------(sends sensors and errors status to server) -----------------
// ---------------------------------------------------------------------------------------

 if (client.connect(serverName, 80)) {
   
   Serial.println("Connected - GET #1");
 
   client.print("GET /sensors.php?temp=");client.print(temp);
   client.print("&light=");client.print(light);
   client.println(" HTTP/1.1");
   
   client.println("Host: myserver.example.org");
   client.println("Connection: close");
   client.println();
   client.stop();
   delay(50);

   Serial.println("GET #1 - disconnecting.");
   } else {
   // if you didn't get a connection to the server:
   Serial.println("GET #1 - connection failed");
}
//  ------------------------- End of GET #1
//
//      
// -------------------------- GET #2 --------------------------------------------------
// -------------------------- (reads the values to be assigned to the LEDs ------------    
// ------------------------------------------------------------------------------------
 
   if (client.connect(serverName, 80)) {
   
   Serial.println("Connected - GET #2");

   client.println("GET /led.txt HTTP/1.1");
   client.println("Host: myserver.example.org");
   client.println("Connection: close");
   client.println();
   client.stop();
   delay(50);

// read the TXT file
   readValue = readPage(); // Call to readPage(): get the values extracted from led.txt file

// assign the LEDs values
LED1 = readValue[0]-'0';
LED2 = readValue[1]-'0';
digitalWrite(ledPinR,LED1);
digitalWrite(ledPinW,LED2);

 } else {
   // if you didn't get a connection to the server:
   Serial.println("GET #2 - connection failed");
   client.stop();
 }
// ------------------------------- End of GET #2 cycle

// note the time that the connection was made:
 lastConnectionTime = millis();
 delay(1000);
//
// store the state of the connection for next time through
// the loop:
 lastConnected = client.connected();

 } // Close HTTP REQUEST
} // Close void LOOP


// ----------------- FUNCTIONS -----------------------------

String readPage(){
// This function
// 1. read a TXT file in the form "<xy>" and
// 2. extract xy and return them (xy can be "00", "01", "10" or "11")
// 3. or return an error code (example "88") in case reads NULL values

// connectLoop controls the hardware fail timeout
 String inString;
 int connectLoop = 0;
 int stringPos = 0;
 
 Serial.println("Read starting...");
 while(client.connected())
 {
   while(client.available())
   {
     char inChar = client.read();
     delay(1);
     inString = inString + inChar;
     // set connectLoop to zero if a packet arrives
     connectLoop = 0;
   }

   connectLoop++;

   // if more than 10000 milliseconds since the last packet
   if(connectLoop > 10000)
   {
     // then close the connection from this end.
     Serial.println();
     Serial.println("Timeout");
     client.stop();
   }
   // this is a delay for the connectLoop timing
   delay(1);
 }

 Serial.println();
 Serial.println("Read finished.");
 // close client
 client.stop();
 delay (1);
 
 // extract and return valid LED values ("00", "01", "10" or "11") or "Error"
 if (inString.length() != 0){ // if inString is not null
 int a = inString.indexOf('<'); // find the position of "<"
 int b = inString.indexOf('>'); // find the position of ">"
 String extracted = inString.substring(a+1,b); // extract the text between "<" and ">"
 delay(1000);

 return extracted;     // return valid values
 } else {return "88"}                     // return some error code
}

SurferTim

You are not reading the response from the server. That will cause the fail you describe.
Code: [Select]
    client.print("GET /sensors.php?temp=");client.print(temp);
    client.print("&light=");client.print(light);
    client.println(" HTTP/1.1");
   
    client.println("Host: myserver.example.org");
    client.println("Connection: close");
    client.println();
    // this will cause problems
    client.stop();
    delay(50);

From my testing, if any characters sent from the server end up in the rx buffer before the connection gets the client.stop(), the connection will not close properly and the socket is no longer available. Three more like that and there will be no sockets available.

kev8

Uh, his is a good point.. and a stupid error due to first time programming for HTTP communication!
I was sure that since I was pushing some variables, the server did not have to answer.. instead the GET method requires an answer in any case.
So, adding the reading of the answer is better.. fewer or no errors.

Sometimes (some hours) it still stops working, but I think it is related to some out-of-memory issue (my real code is about 20K.. there are a lot of debugging checks and Serial.prints). I'll try to reduce it and to increase the delay between two server requests and see if the code remains stable for some days..

Thank you Surfer and other people, it was an honor to have prompt answers from all of you!
(.. and Happy New Year)

Go Up