non blocking Ethernet.begin() with cable disconnected & static IP ?

Baptistou

Member
Hello,

I just received the wonderful new Teensy 4.1 + native ethernet kit.
I'm working on a project which aims to transfer data on a local ethernet network as long as physical serial interfaces. I use static IPs for now.

Question is : is there a way to avoid the "Ethernet.begin(mac, ip);" function to lock down the program if no ethernet cable is connected ? With DHCP I see there is a timeout of 60 seconds, but it doesn't seem to be the case with static IPs. How to test if a cable is there ? Set up a timeout ? Bypass Ethernet.begin(mac, ip) when no cable is there ?

My device should be able to run and do stuff on the physical interfaces even if it is not connected to any ethernet network.

Any clue ?

Baptistou
 
Look for the other thread or so that discusses this, seems there was a similar question recently that might have a ready answer.
 
Hello, sorry I went through the forums and never found the answer yet. Most of threads talk about DHCP and not fixed IP.
 
The post I saw was found it with forum search on : "Ethernet.begin"

Second link : T4.1 Ethernet Library , this post pjrc.com/threads/60857-T4-1-Ethernet-Library Suggests the one sample has a way to detect an active link?
"For example the link-status example doesn't work apart if you add the ethernet begin before testing for the link."
 
I did that search already. Also, the second post you link to mentions the same issue which has not been solved apparently.
Digging into NativeEthernet.cpp, I can see that the Ethernet.begin() in manual mode has this line at the bottom of the function :
Code:
while(!link_status){
}
which definitely locks the program until a cable is connected. I just removed the line, and put link_status checks inside my main program instead, to allow me to do further things while disabling all ethernet related stuff until link_status comes true. This seems to work OK. But is there a better way of doing this instead of modifying libraries inside teensyduino (which I hate to do, as it may make things become unstable - I'm a bad programmer - and also make things not portable from a computer to another, or in case of update / reinstallation) ?
 
I did that search already. Also, the second post you link to mentions the same issue which has not been solved apparently.
Digging into NativeEthernet.cpp, I can see that the Ethernet.begin() in manual mode has this line at the bottom of the function :
Code:
while(!link_status){
}
which definitely locks the program until a cable is connected. I just removed the line, and put link_status checks inside my main program instead, to allow me to do further things while disabling all ethernet related stuff until link_status comes true. This seems to work OK. But is there a better way of doing this instead of modifying libraries inside teensyduino (which I hate to do, as it may make things become unstable - I'm a bad programmer - and also make things not portable from a computer to another, or in case of update / reinstallation) ?

You did what that post hinted at it seems with link_status.

And indeed nothing else has been posted - other than THAT as w solution/work around.

A better way may be out there or arrive - but until then ...
 
Admittedly that is a draw back with the NativeEthernet library, but I’ve tried to keep its functionality as close to how the W5500 works as I can remember. Being that it is blocking in nature I strongly suggest anyone wanting more control to learn FNET by itself since for true non-blocking behavior all around things have to be coded in just right. Which to anyone who was familiar with using Ethernet.h it’s completely different in every way. I’m not sure if it makes sense to implement non-blocking functions into NativeEthernet directly when the functions are already available when FNET is used directly. If anything I would consider adding a non-blocking Ethernet.begin so at least people don’t have to worry about setting it up since that sequence won’t change from sketch to sketch.
 
Hello Vjmuzik, thanks for your explanations. Yes it makes sense to keep NativeEthernet equivalent and fully compatible with former ethernet libraries. Maybe a #ifndef NON_BLOCKING_ETHERNET could be added, to allow to easily pass through the loop mentionned above. If I have the time I'll try to learn FNET more deeply. Thanks again !
 
I modified the wait for link status loop with a timeout counter. If it fails, it times out with an enet_ready flag set. In the main program loop, I have a timer that causes it to retry the init periodically. Additionally, ethernet related TX and RX code looks at that enet_ready flag as a condition of execution to prevent getting into timeouts for hardware that is not ready now but may be ready later. Even if the link is here at init, it may not be there later.

In my usage the ethernet is only a requirement for remote monitor and control. It has to operate 24/7 controlling local equipment with or without ethernet.
 
Are you re-calling begin() from that timer in the loop? I have the same problem and am wondering whether your solution is what I should also do. I assume that the enet_ready flag is something you added and you just query it before any ethernet activity?
 
Correct, I added the flag and check it at each enet usage. If it is not ready, and see that it should be (hardware was found, library started), then I start a timer and try to reinit the connection if possible. I have implemented on 3 projects, 2 are basically the same and quick testing it seems to work to There are some delays encountered during reinit as I recall. MY latest SDR project I went a bit further and have user profiles that add a setting to ignore enet functions also - so even if the enet functionality is #defined, it won't use any of the functions including enet.begin(). This is to cover the case of portable use and bypass startup or retry delays since there will be no wired connection on a tripod mounted radio in the field.

You can look at the code for these projects are on GitHub at
Rotator Controller
RF Wattmeter
The SDR project is here, most of the enet related code is in SDR_Network.cpp and Radio_Config.h.

The description of the simple library patch I made is at the end of SDR_Network.cpp. I posted it below here. Use of a real timer would be better. The enet_flag is in my code only.

/* Mod required for NativeEthernet.cpp file in Ethernet.begin class.
* At end of the function is a statement that hangs if no ethernet cable is connected.
*
* while(!link_status){ // original loop
* return;
* }
*
* You can never progress to use the link status function to query if a cable is connected and the program is halted.
*
* Add the below to let it escape. Use the enet_ready flag to signal if enet started OK or not.
*
uint16_t escape_counter = 0;
while(!link_status && escape_counter < 200){ // modified loop with escape counter
escape_counter++;
Serial.println("Waiting for Link Status");
delay(10);
return;
}
*
*/

- Mike
 
Thanks Mike, that's really useful and something like that may be the way forward. I am working on a device that controls data sampling and acquisition from a number of sensors. A number of ethernet clients can connect, or critically, none and in the latter case there may be no cable connected either.
 
I have another Ethernet library you can try:
https://github.com/ssilverman/QNEthernet

It’s based on lwIP instead of FNET, as an alternative for those who are more familiar with that stack.

Its Ethernet.begin() is non-blocking and you can poll linkStatus() for changes. I’m thinking of adding a link-status callback in a near-future release. Also, it doesn’t use timers; instead, it uses yield() to call things (via EventResponder). Any callbacks (currently) would not be called from an ISR context.
 
Hello,

I know it is an old thread, but "now" (I don't know when it was added), with NativeEthernet, you can use

Code:
Ethernet.begin(mac,0,0)

which does not block (even without ethernet cable) and takes around 5 millis to run (on T4.1). After that you can use

Code:
Ethernet.linkStatus()

to know the status of the link. If no cable was inserted when "begin" was run, and you insert it later, a DHCP address will get assigned in non-blocking.
 
Just from off the top of my head in remembering how I wrote it, that functionality was always there, though unintentionally on my part. Having an IP Address of 0 is what triggers the code to start DHCP when a cable is detected as plugged in. I’ll admit it’s been a while since I’ve messed with anything Ethernet though, other projects I’m working on are eating up my time.
 
i think i was able to hack a workaround using TeensyThreads - basically you can put Ethernet.begin() in a different thread and put a timeout in your main thread (or vice versa) for things to keep moving if Ethernet.begin() can't connect. Seems to be working fine- any potential issues I should be aware of? Looks something like this:
Code:
#include <NativeEthernet.h>    //use for teensy
#include <NativeEthernetUdp.h> //use for teensy
#include <TeensyThreads.h>

IPAddress ip(192, 168, 1, 177); //IP address of this microcontroller
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; //mac address

volatile boolean connectedToEth = false;
void ethInit(){
  Serial.println("searching for connection");
  while(1){
    Ethernet.begin(mac,ip);
    connectedToEth = true;
  }
}

void setup() {
  threads.addThread(ethInit);
  while(!connectedToEth&&millis()<10000){
    delay(1000);
    Serial.println("still searching...");
  }
  if(connectedToEth){
    Serial.println("connected to ethernet");
  }
  else{
    Serial.println("running without ethernet");
  }
}
 
Note that QNEthernet’s Ethernet.begin() is non-blocking. Also, you don’t have to specify a MAC address.
 
Back
Top