robust ethernet library - where can I find one?

Does anyone know of an ethernet library that is a little more robust than what comes with the Arduino IDE?

Specifically, I'd like something that allows direct resetting of the W5100 chip, or more preferably, something that recovers better from inability to establish an ethernet connection. The current library just seems to hang, and not recover well. I realize it has a 60-sec timeout, but that it doesn't get you anywheres. Specifically, the system with ethernet shield works 100%, except for

  1. if you use begin(), and there is no router connected, it hangs, and won't recover.

  2. if you plug in the router cable while it's executing begin(), it doesn't care, and still won't connect.

  3. if you wait for the 60-sec timeout, and plug in the ethernet cable, and then try begin() again, it still won't connect. So, the 60-sec timeout seems to be fairly useless, there seems to be no recovery.

  4. the only way to get it to connect after the preceding is to reset the Arduino chip.

At least that's how it seems to work with me.

So, I figure having a way to (a) directly reset the W5100 chip, or else (b) having a better recovery procedure in the code, will help get this to go. A communications system needs a good capability for graceful error recovery, but I don't seem to see it. Am I missing something here?

My results don’t show that.
#1 - untrue.It will recover.
#2 - untrue. It will get an ip and connect.
#3 - untrue. It will get an ip and connect.
#4 - untrue. It doesn’t need a reset.

Here is my test code. Feel free to torture the crap out of it. I can pull the CAT5 out anywhere in this code and it doesn’t lock up. I tried all your scenarios, and all worked ok. Must be your code. It isn’t the library.

#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[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 };

// Initialize the Ethernet client library
// with the IP address and port of the server 
// that you want to connect to (port 80 is default for HTTP):
EthernetClient client;

int freeRam() {
  extern int __heap_start,*__brkval;
  int v;
  return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int) __brkval);  
}

void setup() {
  // start the serial library:
  Serial.begin(9600);

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

  Serial.print(F("SRAM left: "));
  Serial.println(freeRam());
  
  // start the Ethernet connection:
  Serial.println("Starting ethernet");
  while (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    delay(5000);

  Serial.print(F("SRAM left: "));
  Serial.println(freeRam());


    Serial.println("trying DHCP again");
  }
  // print your local IP address:
  Serial.print("My IP address: ");
  for (byte thisByte = 0; thisByte < 4; thisByte++) {
    // print the value of each byte of the IP address:
    Serial.print(Ethernet.localIP()[thisByte], DEC);
    Serial.print("."); 
  }
  Serial.println();
}

void loop() {
  byte updateVal = Ethernet.maintain();

  if(updateVal) {
      
    Serial.print(F("DHCP maintain..."));
  
    switch(updateVal) {
      case 0:  Serial.println(F("no action"));
              break;

      case 1:  Serial.println(F("renew failed"));     
              break;
              
      case 2:  Serial.println(F("renew success"));           
              break;

      case 3:  Serial.println(F("rebind failed"));           
              break;

      case 4:  Serial.println(F("rebind success"));           
              break;

      default:  Serial.println(F("unknown"));
    }      
  }

  delay(1000);
}

Thanks very much Tim, I will test this and try to determine the difference from what I am doing.

If you have a SD card in the slot, omitting this will cause that fail.

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

Got the PC fired up now, so on to testing. No SD card currently in use. I do have multiple devices all using SPI [ethernet, ColorLCD, RFM12 w/level-shifters, and eventually SD card, plus SPI SRAM and eeprom chips], and have had to do some work to make them all play nicely together, along the lines of your last post. And need to make sure they all have good error recovery. Later.

My advice: Disable all SPI devices in setup() before doing anything. Then initialize one at a time, starting with the most critical device. I always do the SD first because I have my network settings on the SD card.

That's exactly the sort of thing I am doing. Ok, have some further info. I tried your sketch, including all CS disables. I deleted this code, so it will always print out,

//  if(updateVal) { 
...
//  }

I am using an ATmega1284 board for my main system, but also tried it on my Duemilanove board that has a UNO-bootloader chip plugged in.

What I found is that, with both 1284 and UNO, it will recover if you start the program with the router cable unplugged, and then plug it in. After you plug it in, it does obtain an IPaddress after a couple of seconds.

However, the loop() code doesn't care if the cable is unplugged or not, so maintain() doesn't seem to do much. Here are the printouts for the UNO. I disconnected the router cable after a couple of loops, but it always gets the same return code. Try this on your system.

SRAM left: 1442 Starting ethernet My IP address: 192.168.1.141. DHCP maintain...no action DHCP maintain...no action DHCP maintain...no action DHCP maintain...no action DHCP maintain...no action DHCP maintain...no action DHCP maintain...no action

In this case, I had unplugged everything from my 1284 board except for the ethernet shield. For some reason, those other boards prevent the system from recovering when the router cable is plugged in after startup, even though their CS lines are all de-asserted. So, need more grinding.

You should look closely at that code. You should never see that message. That is "case 0:". If updateVal is not zero, it runs the dhcp maintain function. But the return should never be zero.

  if(updateVal) {
      
    Serial.print(F("DHCP maintain..."));
  
    switch(updateVal) {
      case 0:  Serial.println(F("no action"));
              break;

???

Your original code is as follows, so I assume it runs maintain() every single loop.

void loop() {
  byte updateVal = Ethernet.maintain();

  if(updateVal) {
   .....
  }

So, by commenting out if(updateVal), I'm simply displaying the return value each time. And like I said, it makes no difference to maintain() if the router cable is plugged in or not.

That is correct. If the dhcp lease was 2 days, that function does nothing for 1 day. Nothing. It does not contact the dhcp server AT ALL. Only when the lease has reached 1/2 the lease time does it attempt to renew the lease. Until then, the function does not contact the dhcp server. It returns 0, “no action”.

Ok, that explains a lot. I guess I can do a workaround on my original problems - already half implemented. Thanks for all the help, :-).

I'm not quite sure why begin() didn't treat the belated router cable plugin correctly when done inside my program, but I've pulled all that out to the startup routines now, and use a flag to tell go/no-go down in the program. Onwards.