Ethernet reliability?

I've been playing with some telnet code which sends a command message every second to an ethernet PSU, the PSU should respond to the command every time.
The code should send a command ("MI\n") every second at the start of the loop(), which I believe it is doing, but sometimes it fails to reply.

As a test, I have also written some code on the PC to do the same thing to make sure it isn't the PSU not responding, it always replies with the PC version.

Are there any known reliability issues, or perhaps I'm doing something wrong?
I based the code on this:

#include <SPI.h>
#include <Ethernet2.h>

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
IPAddress ip(192, 168, 0, 10);

// Enter the IP address of the server you're connecting to:
IPAddress server(192, 168, 0, 99);

// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 23 is default for telnet;
// if you're using Processing's ChatServer, use port 10002):
EthernetClient client;

unsigned long current_micros = 0;

void setup() {
  // start the Ethernet connection:
  Ethernet.begin(mac, ip);
  // Open serial communications and wait for port to open:
  Serial.begin(115200);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }


  // 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(server, 10001)) {
    Serial.println("connected");
  } else {
    // if you didn't get a connection to the server:
    Serial.println("connection failed");
  }
}

void loop() {
  unsigned long TimerDiff = micros()- current_micros;
  if (TimerDiff >= 1000000)
  {
    current_micros = micros();
    client.print(String("MI\n"));
    Serial.print(String("MI\n"));
  }
  // if there are incoming bytes available
  // from the server, read them and print them:
  if (client.available()) {
    char c = client.read();
    Serial.print(String(c) + ":");
    Serial.print(c,HEX);//print the hex code too
    Serial.print(String("  "));//space out the characters returned
  }

  // as long as there are bytes in the serial queue,
  // read them and send them out the socket if it's open:
  while (Serial.available() > 0) {
    char inChar = Serial.read();
    if (client.connected()) {
      client.print(inChar);
    }
  }

  // if the server's disconnected, stop the client:
  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
    // do nothing:
    while (true);
  }
}

After changing USB cable to one half the diameter but with added ferrites at each end, reliability seems better, I suspect the problem is with the serial comms over USB being corrupted.
I guess that means I should to implement a telnet server on the arduino for monitoring instead of using the USB serial comms...

You are reading only one character at a time? Change the "if" to a "while" and read them all. You will have to redo the rest of your code to print the result. I recommend doing away with the String data type and use character arrays instead.

  if (client.available()) {
    char c = client.read();
    Serial.print(String(c) + ":");
    Serial.print(c,HEX);//print the hex code too
    Serial.print(String("  "));//space out the characters returned
  }

My first attempts at comms did use while, but I seemed to be getting half messages, so my plan was to look for CR and/or LF and timeout if they never came.
So, I've changed the code to grab the whole message:

#include <SPI.h>
#include <Ethernet2.h>

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
IPAddress ip(192, 168, 0, 10);

// Enter the IP address of the server you're connecting to:
IPAddress server(192, 168, 0, 99);

// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 23 is default for telnet;
// if you're using Processing's ChatServer, use port 10002):
EthernetClient client;

unsigned long current_micros = 0;

void setup() {
  // start the Ethernet connection:
  Ethernet.begin(mac, ip);
  // Open serial communications and wait for port to open:
  Serial.begin(115200);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  // 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(server, 10001)) {
    Serial.println("connected");
  } else {
    // if you didn't get a connection to the server:
    Serial.println("connection failed");
  }
}

void loop() {
  unsigned long TimerDiff = micros()- current_micros;
  if (TimerDiff >= 1000000)
  {
    current_micros = micros();
    //flush chars in buffer
    while(client.available()) {char c = client.read();}
    client.print(String("MI\n"));
    Serial.print(String("MI:"));
    bool wait = true;
    String msg = "";
    unsigned long curTime = micros();
    while (wait)
    {
      while (client.available())
      {
        char c = client.read();
          msg = msg + String(c);
          Serial.print(c,HEX);
          Serial.print(String(":"));
          wait = false;
      }
      if ((micros() - curTime) >= 1000000)
      {
        Serial.println(String("Timeout with [") + msg + "] in buffer");
        wait = false;
      }
    }
    Serial.print("\n");
    Serial.println(String("Message: ") +msg);
  }
  // if the server's disconnected, stop the client:
  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
    // do nothing:
    while (true);
  }
}

The result is a mess: (the first 3 lines after connection are correct, println is effectively adding the blank line)

connecting...
connected
MI:4D:49:2C:30:2E:30:30:41:D:A:
Message: MI,0.00A

MI:4D:49:2C:30:
Message: MI,0
MI:4D:49:2C:
Message: MI,
MI:Timeout with [] in buffer

Message: 
MI:4D:49:
Message: MI
MI:4D:49:2C:30:2E:30:30:41:D:A:
Message: MI,0.00A

I need to be able to grab the whole message to do things with it, not just pass it to the serial link, hence the change in code to create a message string.

If you are communicating with a telnet server, the first thing sent to the client will be configuration data.

The PSU which is the telnet server doesn't mention that, and I'm not seeing any data when I connect, so I suspect this doesn't apply.
Using Putty etc.. doesn't show anything when I connect, I think this is normal for this device

It doesn't prompt for a user and password? If not, it isn't very secure.

It won't be connected to the net so it's not a problem.
It's one of these:

I've modified the loop to wait for LF to be received before continuing, with a massive 10 second timeout.

void loop() {
  unsigned long TimerDiff = micros()- current_micros;
  if (TimerDiff >= 1000000)
  {
    current_micros = micros();
    client.print(String("MI\n"));
    Serial.print(String("MI:"));
    bool wait = true;
    String msg = "";
    unsigned long curTime = micros();
    while (wait)
    {
      while (client.available())
      {
        char c = client.read();
        Serial.print(c,HEX);
        Serial.print(String(":"));
        if (c != 13)
        {
          if (c != 10)
          {
            msg = msg + String(c);
          }
        }
        if (c == 10) {wait = false;}
      }
      if ((micros() - curTime) >= 10000000)
      {
        Serial.println(String("Timeout with [") + msg + "] in buffer");
        wait = false;
      }
    }
    Serial.print("\n");
    Serial.println(String("Message: ") +msg);
  }
  // if the server's disconnected, stop the client:
  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
    // do nothing:
    while (true);
  }
}

It's looking a lot better but I'm getting timeouts with no bytes received.#
I can't see why this works fine on a PC with basically the same code, but fails to get a response sometimes on the arduino.

connecting...
connected
Message: MI,0.00A
MI:4D:49:2C:30:2E:30:30:41:D:A:
Message: MI,0.00A
MI:4D:49:2C:30:2E:30:30:41:D:A:
Message: MI,0.00A
MI:Timeout with [] in buffer

Message: 
MI:Timeout with [] in buffer

Message: 
MI:4D:49:2C:30:2E:30:30:41:D:A:
Message: MI,0.00A
MI:4D:49:2C:30:2E:30:30:41:D:A:
Message: MI,0.00A
MI:Timeout with [] in buffer

Message: 
MI:4D:49:2C:30:2E:30:30:41:D:A:
Message: MI,0.00A

Well, after re-powering everything, it seems to be working.
The USB connection is stiil rubbish tho, look at the difference between the serial output of these 2 loops:

MI:4D:49:2C:30:2E:30:30:41:D:A:
Response took 23703
Message: MI,0.00A
MI:4D49:2C:30:2E:30:30:41:D:A:
Response took 2963
Message: MI,0.00A

The 2nd is missing a ':' between 4D and 49, I suspect the USB data got corrupted and it got dropped :frowning:

How often does the PSU send a packet? If it is more often than 15 to 20 per second, it could cause problems with a Mega or Uno. I had to migrate my code to a Due for 30 packets per second.

It only sends a packet when I send a command, I've set the rate to 1 per second.
The data above is via the USB serial link, the ':' are being put in by the Arduino (Due as it happens), but it is getting dropped, probably due to a USB corruption.
It must be a USB issue because:

char c = client.read();
Serial.print(c,HEX);
Serial.print(String(":"));

for every hex code printed there is a ':'

I think I've proved it's not the Arduino/Ethernet Shield doing anything wrong, I wrote a telnet server on the PC to mimic the PSU, it responds every time.
I also wrote a telnet client on the PC to automatically send commands to the real PSU, it fails to get a response sometimes, much like the Arduino does.

Great logic. That is how you determine which is working correctly and which isn't. Hopefully you will be able to determine why the PSU isn't responding correctly.

The manufacturer asked me to provide a WireShark log of the comms :smiley:
It's quite funny really, my crappy code is more reliable than what is supposed to be a professional bit of kit.