Go Down

Topic: More ethernet client stuff... (Read 2322 times) previous topic - next topic

zoomkat

Borrowing some code from previously posted email test code, I made the below copy/paste code to see why the ethernet client seems to be some what hit or miss on connecting to a server. When an e is sent from the serial monitor, the arduino should connect to my web test file and down load it. The below code seems to work every other time unless the e is sent in rapid succession. Just wondering why it seems to work only every other attempt.

Code: [Select]

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

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192, 168, 1, 102 };
byte gateway[] = { 192, 168, 1, 1 }; // internet access via router
byte subnet[] = { 255, 255, 255, 0 }; //subnet mask
byte server[] = { 208, 104, 2, 86 }; // zoomkat
Client client(server, 80);

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

void setup()
{
  Ethernet.begin(mac, ip, gateway, subnet);
  Serial.begin(9600);
  Serial.println("starting simple arduino client test");
  Serial.println("Send an e via the serial monitor.");
  Serial.println();
}

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

void loop()
{
  byte inChar;
  inChar = Serial.read();
  if(inChar == 'e')
  {
    sendGET();
  }
}

//////////////////////////
  void sendGET()
{
  if (client.connect()) {
    Serial.println("connected");
    client.println("GET /~shb/arduino.txt HTTP/1.0");
    client.println();
  }
  else {
    Serial.println("connection failed");
    Serial.println();
  }
 
    while (client.available()) {
    char c = client.read();
    Serial.print(c);
  }
 
  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting.");
    Serial.println("==================");
    Serial.println();
    client.stop();
  }
}
Google forum search: Use Google Advanced Search and use Http://forum.arduino.cc/index in the "site or domain:" box.

PaulS

First thing I'd do is verify that sendGET is actually called when you think it is.

Is there some reason for not using Serial.available() in loop()?

Is it the client.connect() that fails? Or is it the GET command that fails?

SurferTim

#2
Nov 23, 2011, 12:40 pm Last Edit: Nov 23, 2011, 03:28 pm by SurferTim Reason: 1
Go with PaulS on the Serial.available() check. Serial.read() return an integer -1 if no characters are in the buffer.

If the connection fails, exit the subroutine. That would be closer to the original code.
Code: [Select]
if (client.connect()) {
   Serial.println("connected");
   client.println("GET /~shb/arduino.txt HTTP/1.0");
   client.println();
 }
 else {
   Serial.println("connection failed");
   Serial.println();
   return; // This prevents the rest of the subroutine from running without a connection
 }


Edit: If you look at the original code, you will see I cheat. I don't read the entire response code, just the first character.
If the first character returned is lower than '4', all went fine, otherwise, it calls efail() and exits the subroutine. That is what the "client.peek()" call does at each send. It gets the first character without removing it from the buffer. Then all the rest go out the serial port unremembered. The rest is for "skinware" (humans).


zoomkat

Below is what is returned to the serial monitor when four e are sent. when the first e is sent only "connected" is returned to the serial monitor. When the second e is sent the info from my test page is returned to the serial monitor, starting with the "connection failed". Third e only "connected" is returned, fourth e again returns the page. I'll tinker with the Serial.available(), but i would think a -1 would not pass the if(inChar == 'e') test. Bottom is what is returned when the "return"was added to the code as suggested and four e were sent. I'm somewhat curious as to just what happens when the different client calls are made.

Code: [Select]

starting simple arduino client test
Send an e via the serial monitor.

connected
connection failed

HTTP/1.1 200 OK
Date: Wed, 23 Nov 2011 15:38:30 GMT
Server: Apache
Last-Modified: Sat, 13 Nov 2010 16:31:40 GMT
Accept-Ranges: bytes
Content-Length: 51
Connection: close
Content-Type: text/plain; charset=UTF-8

Woohoo! Your arduino ethernet client works!
zoomkat
disconnecting.
==================

connected
connection failed

HTTP/1.1 200 OK
Date: Wed, 23 Nov 2011 15:38:45 GMT
Server: Apache
Last-Modified: Sat, 13 Nov 2010 16:31:40 GMT
Accept-Ranges: bytes
Content-Length: 51
Connection: close
Content-Type: text/plain; charset=UTF-8

Woohoo! Your arduino ethernet client works!
zoomkat
disconnecting.
==================


With return added:

Code: [Select]
starting simple arduino client test
Send an e via the serial monitor.

connected
connection failed

connection failed

connection failed

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

SurferTim

You gotta wait for the server to respond. It may not (and probably not) be immediate. That is why you see this in my code:
Code: [Select]
// send the request
while(client.connected() && !client.available()) delay(1); // wait for something in the buffer
// now get the stuff


zoomkat


You gotta wait for the server to respond. It may not (and probably not) be immediate. That is why you see this in my code:
Code: [Select]
// send the request
while(client.connected() && !client.available()) delay(1); // wait for something in the buffer
// now get the stuff



I added the while line and that seems to fix the problem. I can now send a string like eeeeeeeeee and the page for each e is returned without any failures. Making progress!
Google forum search: Use Google Advanced Search and use Http://forum.arduino.cc/index in the "site or domain:" box.

SurferTim

After you get something in the buffer for an http request (not email), use this:
Code: [Select]
while(client.connected())
{
    // while you are connected as a client (not a server responding to a client)
    // keep reading until the server disconnects.
    while (client.available())
    {
       char c = client.read();
       Serial.print(c);
    }
}

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



zoomkat

Modified the code and it is still working! Added the test for something in the serial buffer, which should will allow for later adding other conditional test such as pins high/low or changed analog values. Maybe next project is to add the server function to allow both client and server to run if possible (server looping for input data until a condition is met where the client function is called to send out data). 

Code: [Select]

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

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192, 168, 1, 102 };
byte gateway[] = { 192, 168, 1, 1 }; // internet access via router
byte subnet[] = { 255, 255, 255, 0 }; //subnet mask
byte server[] = { 208, 104, 2, 86 }; // zoomkat web site
Client client(server, 80);

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

void setup()
{
  Ethernet.begin(mac, ip, gateway, subnet);
  Serial.begin(9600);
  Serial.println("starting simple arduino client test");
  Serial.println("Send an e via the serial monitor.");
  Serial.println();
}

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

void loop()
{
  if (Serial.available() > 0)
  {
    byte inChar;
    inChar = Serial.read();
    if(inChar == 'e')
    {
      sendGET();
    }
  }
}
//////////////////////////
void sendGET()
{
  if (client.connect()) {
    Serial.println("connected");
    client.println("GET /~shb/arduino.txt HTTP/1.0");
    client.println();
  }
  else {
    Serial.println("connection failed");
    Serial.println();
  }

  while(client.connected() && !client.available()) delay(1);
  while (client.available()) {
    char c = client.read();
    Serial.print(c);
  }

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

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

SurferTim

Code: [Select]
while(client.connected() && !client.available()) delay(1);

// here.
  while (client.available()) {
    char c = client.read();
    Serial.print(c);
  }
// to here

You might get into a bit of trouble here. If the server is bandwidth throttled, you might empty the receive buffer before the server is finished sending. Wait for the server to close the connection. That is the signal it is finished sending, or the connection was broken.

PaulS

Quote
Modified the code and it is still working!

Keep working on it. You'll break it yet.  8)

zoomkat

#10
Nov 23, 2011, 08:22 pm Last Edit: Nov 24, 2011, 11:42 pm by zoomkat Reason: 1
Changed the code to the below with the assumption that the server will close the connection on its end when it finishes sending the data.

Code: [Select]

 while(client.connected() && !client.available()) delay(1);
 while (client.connected() || client.available()) {
   char c = client.read();
   Serial.print(c);
 }
Google forum search: Use Google Advanced Search and use Http://forum.arduino.cc/index in the "site or domain:" box.

SurferTim


Chabged the code to the below with the assumption that the server will close the connection on its end when it finishes sending the data. (snip)

It will, with the assumption that the person that wrote the server code (maybe you shortly?) does that.
Server end:
Code: [Select]
client.write("</body></html>\r\n\r\n"); // last line of the html
client.stop(); // disconnect. This is the signal you are finished.



zoomkat

It appears that for client operation behind a netgear home router, the client code works without the router gateway and subnet values. Might simplify the setup as long as the first three parts of the router and arduino IP addresses are the same.

Code: [Select]

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

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192, 168, 1, 102 }; // arduino lan IP
//byte gateway[] = { 192, 168, 1, 1 }; // internet access via router
//byte subnet[] = { 255, 255, 255, 0 }; // subnet mask
byte server[] = { 208, 104, 2, 86 }; // zoomkat web site
Client client(server, 80);

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

void setup()
{
  Ethernet.begin(mac, ip);
  //Ethernet.begin(mac, ip, gateway, subnet);
  Serial.begin(9600);
  Serial.println("starting simple arduino client test");
  Serial.println("Send an e via the serial monitor.");
  Serial.println();
}

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

void loop()
{
  if (Serial.available() > 0)
  {
    byte inChar;
    inChar = Serial.read();
    if(inChar == 'e')
    {
      sendGET();
    }
  }
}
//////////////////////////
void sendGET()
{
  if (client.connect()) {
    Serial.println("connected");
    client.println("GET /~shb/arduino.txt HTTP/1.0");
    client.println();
  }
  else {
    Serial.println("connection failed");
    Serial.println();
  }

  while(client.connected() && !client.available()) delay(1); //waits for data
  while (client.connected() || client.available()) { //connected or data available
    char c = client.read();
    Serial.print(c);
  }

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

}

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

SurferTim

#13
Nov 25, 2011, 01:03 pm Last Edit: Nov 25, 2011, 01:21 pm by SurferTim Reason: 1
Unless you entered the gateway and subnet incorrectly, it would not make a difference. In your case the gateway would be set to 192.168.1.1 with subnet 255.255.255.0. These are the Ethernet.begin() functions in ethernet.cpp:
Code: [Select]
// this is the one you called:
void EthernetClass::begin(uint8_t *mac, uint8_t *ip)
{
 // this generates a gateway with the first three numbers from your ip and adds a '1' for the last.
 uint8_t gateway[4];
 gateway[0] = ip[0];
 gateway[1] = ip[1];
 gateway[2] = ip[2];
 gateway[3] = 1;
 begin(mac, ip, gateway); // then this calls the function below
}

void EthernetClass::begin(uint8_t *mac, uint8_t *ip, uint8_t *gateway)
{
 // this uses 255.255.255.0 for a subnet
 uint8_t subnet[] = {
   255, 255, 255, 0   };
 begin(mac, ip, gateway, subnet); // then this calls the function below
}

void EthernetClass::begin(uint8_t *mac, uint8_t *ip, uint8_t *gateway, uint8_t *subnet)
{
 // this sets all the stuff whether you entered it or not.
 W5100.init();
 W5100.setMACAddress(mac);
 W5100.setIPAddress(ip);
 W5100.setGatewayIp(gateway);
 W5100.setSubnetMask(subnet);
}



Go Up