Networking-for-Arduino / EthernetENC

Ethernet library for ENC28J60. This is a modern version of the UIPEthernet library. EthernetENC library is compatible with all Arduino architectures with Arduino SPI library with transactions support. Only include EthernetENC.h instead of Ethernet.h
131 stars 29 forks source link

client.write("somestring") fails after a random amount of calls #7

Closed rcamprodon closed 3 years ago

rcamprodon commented 3 years ago

Hi: I have a strange behaviour of EthernetClient client.write("somestring") returning zero bytes after a random number of calls. My application is running on a Nano Every and a Enc28J60 shield (lots of code ommited for clarity):

#include <Arduino.h>
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress clientIP(192, 168, 1, 177);
EthernetClient client;
int serverPort = 2323;
IPAddress serverIP(192, 168, 1, 80);

void setup() {
    if (initEth()) {
        isConnected = connectToFrame(serverIP, serverPort);
    }
    if (!isConnected) {
        Debug(msgNoEthLink);
               // FAULT
    }
}
long last_loop;
#define LOOP_PERIOD 50
void loop() {
    if (millis() > last_loop + LOOP_PERIOD) {
        last_loop = millis();
        reConnect(serverIP, serverPort); // in case the connection is lost
        readEncoder();  // when there is a change in the encoder value, it sends a message to the server
        readClient();     // receives then parses JSON from the server
        readPushBtns(); // when there is a change in the encoder value, it sends a message to the server

// HERE IS THE HACK WICH SOLVES MY PROBLEM
// BUT I DON'T KNOW WHY (!!?)
        client.write((byte)0);

        }
    }

When a change is read in the encoder i send a message like this:

int sendCmd(const char *control, const char *param, int value) {
    int num = -1;
    int a, l;
    sprintf(strbuf, "{\"OP\":\"cmd\",\"Control\":\"%s\",\"%s\":%i}", control,
            param, value);
    num = client.println(strbuf);
        client.flush(); // TRIED THIS BUT NO CHANGE IN BEHAVIOUR
    sentCmd = true;
    return num;
}

After several sendCmd I get a return SMALLER than the length of the buffer sent (strbuf, which is a big enough char array) and the next one is zero, forever. I cannot recover from this fail. The client.write("string") returns after the 2000ms timeout without sending data. I traced the error up to Enc28J60Network::allocBlock(UIP_SOCKET_DATALEN); which, apparently, returns NOBLOCK. The only solution is to continuously client.write((byte)0); on the main loop, which is not really elegant and very brute-force. I also tried to check client.availableForWrite() before sending a message, but no luck, it is always correct.

Any idea?

JAndrassy commented 3 years ago

what is on server side?

rcamprodon commented 3 years ago

Either a terminal program (YAT) i server mode, a Lazarus dummy server I wrote, or the real device which is controlled (STM32F4)with my server side software which is working well with desktop applications.

rcamprodon commented 3 years ago

I did a very basic test with the bare Arduino IDE, and sending in a timed loop (say 10 messages/second) failed after a random amount of loops. Only worked after adding the client.write((byte)0);

JAndrassy commented 3 years ago

add Ethernet.maintain() to loop() so the library can handle the network traffic. because you don't call the library functions frequently enough to handle everything. write(0) was one more call in which the library can handle things

rcamprodon commented 3 years ago

I already tested this. I forgot to mention. I'll try to substitute write(0) for maintain().

JAndrassy commented 3 years ago

I already tested this. I forgot to mention. I'll try to substitute write(0) for maintain().

call maintain in every loop, not in the if write calls 'tick' repeatedly until timeout if it can't allocate space . maintain calls tick only once