New lwIP-based Ethernet library for Teensy 4.1

I can’t speak for QNEthernet but NativeEthernet doesn’t have MDNS lookup so .local addresses won’t work.
 
I can’t speak for QNEthernet but NativeEthernet doesn’t have MDNS lookup so .local addresses won’t work.

Thanks, I did try without the '.local' but it failed to connect as well. I cannot remember if I tried with NativeEthernet. I will try it again.
 
Try setting LWIP_DNS_SUPPORT_MDNS_QUERIES to 1 in lwipopts.h (line 148). I think I'll add this to the next release.

Side point: the "(const char *)" casts aren't needed.
 
Try setting LWIP_DNS_SUPPORT_MDNS_QUERIES to 1 in lwipopts.h (line 148). I think I'll add this to the next release.

Side point: the "(const char *)" casts aren't needed.

Thanks. I'll check it out. As you can tell I am really new to all of this:)
 
A little help please. Can anyone tell me why my code is returning 0.0.0.0 for my server address? I've tried NativeEthernet and Shawn's QNEthernet and both give me the same result. If I pass it my mac and IP then I do get my server ip to be the one I passed but every browser I use tells me connection refused....

Here's my simple code:

/*
Web Server

A simple web server that shows the value of the analog input pins.
using an Arduino Wiznet Ethernet shield.

Circuit:
* Ethernet shield attached to pins 10, 11, 12, 13
* Analog inputs attached to pins A0 through A5 (optional)

created 18 Dec 2009
by David A. Mellis
modified 9 Apr 2012
by Tom Igoe
modified 02 Sept 2015
by Arturo Guadalupi

*/

#include <SPI.h>
#include <QNEthernet.h>
using namespace qindesign::network;// ADD for QNEthernet

// Enter a MAC address and IP address for your controller below.
byte mac[] = {0x08, 0x97, 0x98, 0x6C, 0x4E, 0x8C};
byte ip[] = { 169, 254, 240, 149 }; // ip in lan
byte gateway[] = { 0, 0, 0, 0 }; // internet access via router
byte subnet[] = { 255, 255, 0, 0 }; //subnet mask

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

void setup() {
// You can use Ethernet.init(pin) to configure the CS pin
//Ethernet.init(10); // Most Arduino shields
//Ethernet.init(5); // MKR ETH shield
//Ethernet.init(0); // Teensy 2.0
//Ethernet.init(20); // Teensy++ 2.0
//Ethernet.init(15); // ESP8266 with Adafruit Featherwing Ethernet
//Ethernet.init(33); // ESP32 with Adafruit Featherwing Ethernet

// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
stdPrint = &Serial; // ADD for QNEthernet
Serial.println("Ethernet WebServer Example");

// start the Ethernet connection and the server:
Ethernet.begin();
Ethernet.waitForLocalIP(10000);// ADD for QNEthernet

// 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() {
// listen for incoming clients
EthernetClient client = server.available();

if (client) {
Serial.println("new client");
// an http request ends with a blank line
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
Serial.write(c);
// if you've gotten to the end of the line (received a newline
// character) and the line is blank, the http request has ended,
// so you can send a reply
if (c == '\n' && currentLineIsBlank) {
// send a standard http response header
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close"); // the connection will be closed after completion of the response
client.println("Refresh: 5"); // refresh the page automatically every 5 sec
client.println();
client.println("<!DOCTYPE HTML>");
client.println("<html>");
// output the value of each analog input pin
for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
int sensorReading = analogRead(analogChannel);
client.print("analog input ");
client.print(analogChannel);
client.print(" is ");
client.print(sensorReading);
client.println("<br />");
}
client.println("</html>");
break;
}
if (c == '\n') {
// you're starting a new line
currentLineIsBlank = true;
} else if (c != '\r') {
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}
// give the web browser time to receive the data
delay(2);
// close the connection:
client.stop();
Serial.println("client disconnected");
}

}
 
Code:
/*
Web Server

A simple web server that shows the value of the analog input pins.
using an Arduino Wiznet Ethernet shield.

Circuit:
* Ethernet shield attached to pins 10, 11, 12, 13
* Analog inputs attached to pins A0 through A5 (optional)

created 18 Dec 2009
by David A. Mellis
modified 9 Apr 2012
by Tom Igoe
modified 02 Sept 2015
by Arturo Guadalupi

*/

#include <SPI.h>
#include <QNEthernet.h>
using namespace qindesign::network;// ADD for QNEthernet

// Enter a MAC address and IP address for your controller below.
byte mac[] = { 0x08, 0x97, 0x98, 0x6C, 0x4E, 0x8C };
byte ip[] = { 169, 254, 240, 149 }; // ip in lan
byte gateway[] = { 0, 0, 0, 0 }; // internet access via router
byte subnet[] = { 255, 255, 0, 0 }; //subnet mask

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

void setup() {
	// You can use Ethernet.init(pin) to configure the CS pin
	//Ethernet.init(10); // Most Arduino shields
	//Ethernet.init(5); // MKR ETH shield
	//Ethernet.init(0); // Teensy 2.0
	//Ethernet.init(20); // Teensy++ 2.0
	//Ethernet.init(15); // ESP8266 with Adafruit Featherwing Ethernet
	//Ethernet.init(33); // ESP32 with Adafruit Featherwing Ethernet

	// Open serial communications and wait for port to open:
	Serial.begin(9600);
	while (!Serial) {
		; // wait for serial port to connect. Needed for native USB port only
	}
	stdPrint = &Serial; // ADD for QNEthernet
	Serial.println("Ethernet WebServer Example");

	// start the Ethernet connection and the server:
	Ethernet.begin();
	Ethernet.waitForLocalIP(10000);// ADD for QNEthernet

	// 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() {
	// listen for incoming clients
	EthernetClient client = server.available();

	if (client) {
		Serial.println("new client");
		// an http request ends with a blank line
		boolean currentLineIsBlank = true;
		while (client.connected()) {
			if (client.available()) {
				char c = client.read();
				Serial.write(c);
				// if you've gotten to the end of the line (received a newline
				// character) and the line is blank, the http request has ended,
				// so you can send a reply
				if (c == '\n' && currentLineIsBlank) {
					// send a standard http response header
					client.println("HTTP/1.1 200 OK");
					client.println("Content-Type: text/html");
					client.println("Connection: close"); // the connection will be closed after completion of the response
					client.println("Refresh: 5"); // refresh the page automatically every 5 sec
					client.println();
					client.println("<!DOCTYPE HTML>");
					client.println("<html>");
					// output the value of each analog input pin
					for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
						int sensorReading = analogRead(analogChannel);
						client.print("analog input ");
						client.print(analogChannel);
						client.print(" is ");
						client.print(sensorReading);
						client.println("<br />");
					}
					client.println("</html>");
					break;
				}
				if (c == '\n') {
					// you're starting a new line
					currentLineIsBlank = true;
				}
				else if (c != '\r') {
					// you've gotten a character on the current line
					currentLineIsBlank = false;
				}
			}
		}
		// give the web browser time to receive the data
		delay(2);
		// close the connection:
		client.stop();
		Serial.println("client disconnected");
	}

}
Can I suggest that you post your code between code tags using the # button.
That way the code is much more readable and easier to understand as I am sure
you will agree from the example above.
 
A little help please. Can anyone tell me why my code is returning 0.0.0.0 for my server address? I've tried NativeEthernet and Shawn's QNEthernet and both give me the same result. If I pass it my mac and IP then I do get my server ip to be the one I passed but every browser I use tells me connection refused....

Assuming you are using T4.1, have you tried running any of shawn's QNEthernet examples? That would be a good starting point to be sure that your ethernet hardware/software is okay and the basics work, and then move on from there.
 
Code:
/*
Web Server

A simple web server that shows the value of the analog input pins.
using an Arduino Wiznet Ethernet shield.

Circuit:
* Ethernet shield attached to pins 10, 11, 12, 13
* Analog inputs attached to pins A0 through A5 (optional)

created 18 Dec 2009
by David A. Mellis
modified 9 Apr 2012
by Tom Igoe
modified 02 Sept 2015
by Arturo Guadalupi

*/

#include <SPI.h>
#include <QNEthernet.h>
using namespace qindesign::network;// ADD for QNEthernet

// Enter a MAC address and IP address for your controller below.
byte mac[] = { 0x08, 0x97, 0x98, 0x6C, 0x4E, 0x8C };
byte ip[] = { 169, 254, 240, 149 }; // ip in lan
byte gateway[] = { 0, 0, 0, 0 }; // internet access via router
byte subnet[] = { 255, 255, 0, 0 }; //subnet mask

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

void setup() {
	// You can use Ethernet.init(pin) to configure the CS pin
	//Ethernet.init(10); // Most Arduino shields
	//Ethernet.init(5); // MKR ETH shield
	//Ethernet.init(0); // Teensy 2.0
	//Ethernet.init(20); // Teensy++ 2.0
	//Ethernet.init(15); // ESP8266 with Adafruit Featherwing Ethernet
	//Ethernet.init(33); // ESP32 with Adafruit Featherwing Ethernet

	// Open serial communications and wait for port to open:
	Serial.begin(9600);
	while (!Serial) {
		; // wait for serial port to connect. Needed for native USB port only
	}
	stdPrint = &Serial; // ADD for QNEthernet
	Serial.println("Ethernet WebServer Example");

	// start the Ethernet connection and the server:
	Ethernet.begin();
	Ethernet.waitForLocalIP(10000);// ADD for QNEthernet

	// 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() {
	// listen for incoming clients
	EthernetClient client = server.available();

	if (client) {
		Serial.println("new client");
		// an http request ends with a blank line
		boolean currentLineIsBlank = true;
		while (client.connected()) {
			if (client.available()) {
				char c = client.read();
				Serial.write(c);
				// if you've gotten to the end of the line (received a newline
				// character) and the line is blank, the http request has ended,
				// so you can send a reply
				if (c == '\n' && currentLineIsBlank) {
					// send a standard http response header
					client.println("HTTP/1.1 200 OK");
					client.println("Content-Type: text/html");
					client.println("Connection: close"); // the connection will be closed after completion of the response
					client.println("Refresh: 5"); // refresh the page automatically every 5 sec
					client.println();
					client.println("<!DOCTYPE HTML>");
					client.println("<html>");
					// output the value of each analog input pin
					for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
						int sensorReading = analogRead(analogChannel);
						client.print("analog input ");
						client.print(analogChannel);
						client.print(" is ");
						client.print(sensorReading);
						client.println("<br />");
					}
					client.println("</html>");
					break;
				}
				if (c == '\n') {
					// you're starting a new line
					currentLineIsBlank = true;
				}
				else if (c != '\r') {
					// you've gotten a character on the current line
					currentLineIsBlank = false;
				}
			}
		}
		// give the web browser time to receive the data
		delay(2);
		// close the connection:
		client.stop();
		Serial.println("client disconnected");
	}

}
Can I suggest that you post your code between code tags using the # button.
That way the code is much more readable and easier to understand as I am sure
you will agree from the example above.

100% accurate. Sorry as soon as I hit submit I regretted my decision.
 
Assuming you are using T4.1, have you tried running any of shawn's QNEthernet examples? That would be a good starting point to be sure that your ethernet hardware/software is okay and the basics work, and then move on from there.

I've tried many examples, I thought a simple webserver would be the easiest to test. If you have a suggestion on a better example to start with please let me know. I just assumed a web server was the "hello world" level for ethernet coding.

Yes I have a Teensy 4.1 and the Ethernet kit from JPRC. I've run plenty of other code on the T4.1 (SPI, I2C, UART,etc.) so I know the board is good. I've also run Angry IPScanner and pinged the T4.1 with the Ethernet kit connected. That's were I got the MAC and IP address. Running ipconfig through the command line gives me the IP of 196.254.240.149 and the subnet of 255.255.0.0.

It doesn't give me a gateway though...is that why I'm getting an IP address of 0.0.0.0 when I run Ethernet.localIP()?
 
I've tried many examples, I thought a simple webserver would be the easiest to test. If you have a suggestion on a better example to start with please let me know. I just assumed a web server was the "hello world" level for ethernet coding.

Yes I have a Teensy 4.1 and the Ethernet kit from JPRC. I've run plenty of other code on the T4.1 (SPI, I2C, UART,etc.) so I know the board is good. I've also run Angry IPScanner and pinged the T4.1 with the Ethernet kit connected. That's were I got the MAC and IP address. Running ipconfig through the command line gives me the IP of 196.254.240.149 and the subnet of 255.255.0.0.

It doesn't give me a gateway though...is that why I'm getting an IP address of 0.0.0.0 when I run Ethernet.localIP()?

I can't answer that specific question, and the problem may be really simple, but I don't think you should expect examples written for Wiznet will work with just a change from "Ethernet.h" to "QNEthernet.h". If you search for posts by user khoih-prog, you will find links to number of Web Server and other Ethernet libraries with support for QNEthernet.
 
Any thoughts on when or if TLS support examples might be available? Seems to me that any ethernet communication outside the local network needs it.
 
I believe TLS sits on top of TCP/IP. I have no current plans to add it to the library. (Let me see what lwIP has…)
 
Last edited:
I tried making the switch over to QNEthernet this week but I had a few issues/questions.

First issue I noticed was that the data that I was sending from the Teensy to the PC wasn't being received fast enough, I did confirm it was being received but it was coming in rather slow. My application sends data from the Teensy Ethernet server to the pc at least every 50ms. On GitHub it mentions the library sends the data only when the buffer fills or the "internal timer" expires, is there a proper way to change that timer? I believe NativeEthernet was polling every 1ms so I would probably like to match that.

Another question I have is, when using NativeEthernet I had to increase the socket size and heap with setSocketSize and setStackHeap because I was sending larger amounts of data quickly and the buffer would fill up and cause my main loop to hang while NativeEthernet waited for the buffer to free up space for the rest of the data. Is there equivalent settings for QNEthernet so I do not run into this issue again?
 
Call flush() to send any buffered data immediately. For reference, see the “Write immediacy” section in the Readme.

There’s no equivalent for setSocketSize() or setStackHeap(). Those are specific to how NativeEthernet operates. Try flush() first at points where you need to be sure data is sent. If you really need to, you can increase the stack’s heap by changing MEM_SIZE in lwipopts.h, but I don’t feel that will be necessary here.
 
Call flush() to send any buffered data immediately. For reference, see the “Write immediacy” section in the Readme.

There’s no equivalent for setSocketSize() or setStackHeap(). Those are specific to how NativeEthernet operates. Try flush() first at points where you need to be sure data is sent. If you really need to, you can increase the stack’s heap by changing MEM_SIZE in lwipopts.h, but I don’t feel that will be necessary here.

Okay so what I am seeing is by design, just call flush whenever data is time sensitive and if not, I can let the library buffer and send the data when the timer hits to be more efficient? I will try using flush and make sure everything is working properly. The largest amount of data I may send from one write call is currently 4000 bytes, I will make sure this case happens and see how it goes. Thanks for the help.
 
Yes, that’s correct. I chose “buffer if it can” over “send always” because lwIP’s API is similar, so I basically just did a direct mapping. Plus there exists that flush() call in the Arduino API (I don’t really understand why it exists in the Stream class but not in the Print class, because Stream is for reading and Print is for writing).

Additionally, buffering is a feature that’s harder to implement yourself, so I provided mechanisms to do both, the default being buffering. “Let the underlying stack handle it because that’s what it normally does” seemed like the best approach.

I’m very interested in how your project goes. Do let me know (here or otherwise). :)
 
Will I have a similar issue (delay) when I read the response or is it handled differently than writing? I will be sure to let you know how it goes.
 
Under the hood, incoming data is handled with callbacks, but with polling and not interrupts. The stack is polled for input every time Ethernet.loop() is called, which happens in a number of places internally, and also after each call to the main program’s loop() function. And also whenever yield() is called. In short, under normal circumstances you don’t need to worry about calling this; it will be done automatically. I’m willing to bet that for most cases, you will receive data pretty quickly.

Note: one of the examples is an iperf server you can use to test throughput. I’ve been getting about 95Mbps.
 
I have been using this library ever since our last message and everything has been pretty smooth so far. I did find one issue today when testing client reconnection, if you unplug and plug back in the ethernet cable about 7 times in a row you can no longer connect a client to a TCP server.

I am still investigating this but I was able to recreate it with the "ServerWithListeners" example so I believe it may be an issue with the library. This would affect any long running application which may occasionally be unplugged from the network.
 
Back
Top