arduino / ArduinoCore-mbed

330 stars 195 forks source link

EthernetServer inconsistencies #617

Closed KimCranfield closed 1 year ago

KimCranfield commented 1 year ago

Trying to create a simple TCP server on a Portenta Machine control board. To support a single ocasional connection for a configuration interface. Board will run a main loop, with spare time used to poll, parse etc.

I started with the ChatServer example, but that closes the connection as soon as it opens, after first byte transferred.

WebServer example seems to work, but any attempt to move the polling of server.available out of a while loop into the main loop makes it drop the connection.

This works - if after the connection I immediately drop into a while loop to poll for input. Telnet in, connection stays open, bytes sent both ways. Interestingly client.available doesn't return true until there is a newline, but I can work with that.

The printing on no input is just to show activity while debugging.

void loop() {
  // listen for incoming clients
  EthernetClient client = server.available();
  if (client) {
    Serial.println("new client");
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        client.write(c);
      }else {
        Serial.print("n");
        delay(50);
      }
    }
    delay(1);
    // close the connection:
    client.stop();
    Serial.println("client disconnected");
  }
}

But if I restructure to just add a flag and then drop into the while loop if that flag is true (which it is!) it drops the connection immediately after it is opened (Telnet from Linux)

My plan for this flag was to move from a local while loop to an if, calling it from the main loop so the rest of the system keeps running - but even before I got to that, leaving the local while loop, it dies.

void loop() {
  if (not(flagConnected)) {
    // listen for incoming clients
    EthernetClient client = server.available();
    if (client) {
      Serial.println("new client");
      flagConnected=true;
    }
  }

  if (flagConnected) {   
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        client.write(c);
      }else {
        Serial.print("n");
        delay(50);
      }
    }
    delay(1);
    // close the connection:
    client.stop();
    Serial.println("client disconnected");
    flagConnected=false;
  }

}

Using mbed_portenta library from the library manager, v3.5.4 Arduino IDE 1.8.19 Portenta Machine Control board, with H7 and using the M7 core.

Seems to be using Ethernet v1.0.0 from \AppData\Local\Arduino15\packages\arduino\hardware\mbed_portenta\3.5.4\libraries\Ethernet
Not the generic v2.0 library

TCPTerminalTest.io.txt

facchinm commented 1 year ago

Hi @KimCranfield , you are shadowing the global client object with the one that you get from server.available();

  if (not(flagConnected)) {
    // listen for incoming clients
    EthernetClient client = server.available();   <--- this creates a new object
    if (client) {
      Serial.println("new client");
      flagConnected=true;
    }
  } <---- that gets destroyed in this line (when it goes out of scope, closing the connection)

The correct code could resemble

#include <PortentaEthernet.h>
#include <Ethernet.h>

// The IP address will be dependent on your local network:
IPAddress ip(192, 168, 0, 220);

// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
EthernetServer server(80);
bool flagConnected = false;

EthernetClient _client;

char bufferIn[50];
unsigned int iBufferIn;

bool flagBufferValid = true; // flag if buffer has overrun - dump don't parse
unsigned int i = 0;

void setup() {

  // 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
  }
  Serial.println("Stripped Webserver");

  // start the Ethernet connection and the server:
  Ethernet.begin();

  // Check for Ethernet hardware present
  if (Ethernet.hardwareStatus() == EthernetNoHardware) {
    Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
    while (true) {
      delay(1); // do nothing, no point running without Ethernet hardware
    }
  }
  if (Ethernet.linkStatus() == LinkOFF) {
    Serial.println("Ethernet cable is not connected.");
  }

  // start the server
  server.begin();
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
}

void loop() {
  if (not(flagConnected)) {
    // listen for incoming clients
    EthernetClient client = server.available();
    if (client) {
      Serial.println("new client");
      flagConnected = true;
      _client = client;
    }
  }

  if (flagConnected) {
    while (_client.connected()) {
      if (_client.available()) {
        char c = _client.read();
        Serial.write(c);
        _client.write(c);
      } else {
        Serial.print("n");
        delay(50);
      }
    }
    delay(1);
    // close the connection:
    _client.stop();
    Serial.println("client disconnected");
    flagConnected = false;
  }
}
KimCranfield commented 1 year ago

Thank you ! - rookie error.
Sorry for the delay - I did reply that afternoon but I don't think it stuck.