GithubHelp home page GithubHelp logo

vjmuzik / nativeethernet Goto Github PK

View Code? Open in Web Editor NEW

This project forked from paulstoffregen/ethernet

62.0 62.0 23.0 459 KB

Native Ethernet library for Teensy 4.1

Home Page: http://www.pjrc.com/teensy/td_libs_Ethernet.html

License: MIT License

C++ 96.21% C 3.79%

nativeethernet's People

Contributors

ivankravets avatar khoih-prog avatar paulstoffregen avatar pfgimenez avatar rjongeneelen avatar ssilverman avatar vjmuzik avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

nativeethernet's Issues

host_name not declared in EthernetClient

Just udpated my PLatformio native ethernet to a fresh zip from here and get

.platformio\packages\framework-arduinoteensy\libraries\NativeEthernet\src\NativeEthernetClient.cpp: In member function 'virtual int EthernetClient::connect(const char*, uint16_t)':
C:\Users\david.platformio\packages\framework-arduinoteensy\libraries\NativeEthernet\src\NativeEthernetClient.cpp:45:5: error: 'host_name' was not declared in this scope
host_name = host;
^
*** [.pio\build\pre_and_post_hooks\lib37c\NativeEthernet\NativeEthernetClient.cpp.o] Error 1

I assume the host_name is only used for TLS as its declared

#if FNET_CFG_TLS
fnet_tls_desc_t tls_desc = 0;
bool _tls_en = false;
const char* host_name = NULL;
fnet_uint8_t* ca_certificate_buffer = (fnet_uint8_t*)mbedtls_test_ca_crt; /* Certificate data. /
fnet_size_t ca_certificate_buffer_size = mbedtls_test_ca_crt_len; /
Size of the certificate buffer. */
#endif

I assume it can be managed by adding "#if FNET_CFG_TLS" around its use

Ethernet.begin() issue

Hi,

Whenever we try to run a example sketch without the PHY connected to a network, Ethernet.begin(mac) takes approximately 60000 milliseconds to start. If Ethernet.begin(mac, ip) it takes about 18 minutes to start. The moment a network jack is plugged in, Ethernet.begin() immediately executes.

Is there any way to overcome Ethernet.begin() getting stuck while the board is not connected to a network?

Kind regards

Lost UDP packets when sending multiple

I have a case where I periodically want to send a small number 3-4 of small udp packets. When I send 2 in succession only the second one makes it through to the other side.
Is this a bug? should I be checking that the previous packet has been sent somehow?

client.write doesn't return the actual number of bytes written

The official Arduino documentation says the write method will return the number of bytes actually written, as is expected for most socket programming. This library does not do that, and I'm thus unable to properly stream voluminous data. Is there another function I can call subsequent to write to determine the number of bytes just written?

Ethernet MAC ID not unique on Teensy 4.1

It appears that the MAC ID used by the library is not unique. I tested it on 2 Teensy 4.1.
Below is the source piece and the output it generates. It can be seen that even by setting the MAC ID read by Teensy (or another with random values) once Ethernet.begin() is used, the MAC ID is changed to the same value even on two different Teesny4.1s.
Wireshark confirms the MAC ID that is displayed and set by the library.

SOURCE CODE

//Ethernet init
uint8_t macId[32]; //no need to initialize, it is hardcoded
teensyMAC(macId);
SerialDBG_println("MAC ID before Ethernet Begin");
sprintf(buff, "Ethernet mac address: %02X:%02X:%02X:%02X:%02X:%02X \n", macId[0], macId[1], macId[2], macId[3], macId[4], macId[5]);
SerialDBG_println(buff);

Ethernet.begin(macId);
SerialDBG_println("MAC ID after Ethernet begin");
sprintf(buff, "Ethernet mac address: %02X:%02X:%02X:%02X:%02X:%02X \n", macId[0], macId[1], macId[2], macId[3], macId[4], macId[5]);
SerialDBG_println(buff);

Ethernet.MACAddress(macId);
SerialDBG_println("MAC ID after read Ethernet.MACAddress()");
sprintf(buff, "Ethernet mac address: %02X:%02X:%02X:%02X:%02X:%02X \n", macId[0], macId[1], macId[2], macId[3], macId[4], macId[5]);
SerialDBG_println(buff);

OUTPUT

MAC ID before Ethernet Begin
Ethernet mac address: 04:E9:E5:0C:52:73

MAC ID after Ethernet begin
Ethernet mac address: 72:65:73:73:3A:20

MAC ID after read Ethernet.MACAddress()
Ethernet mac address: 72:65:73:73:3A:20

NativeEthernet with long delay instruction or inside IntervalTimer loop function

Good afternoon,
I tried to use the NativeEthernet inside IntervalTimer function, however, after 1-2 minute(s), the NativeEthernet freezes for no appearent reason (it stops receiving packets, however the led on the magjack kit stills work and windows continues sending packets). When i move the NativeEthernet instructions inside the loop function, the NativeEthernet works perfectly (without freeze), except if there is a long delay instruction (as below ; if there is a long delay instruction, NativeEthernet also freezes ).
Below, there is a code that freezes.

Do you know how to solve it ?

Thank you

My Source code:

#include <NativeEthernet.h>
#include <NativeEthernetUdp.h>
EthernetUDP myUDP;
byte ip[] = {192, 168, 1, 177};
byte mac[] = {0x04, 0xE9, 0xE5, 0x00, 0x69, 0xEC};
#define NET_PORT 6450
uint8_t netPacket[1470];
unsigned short packetSize;
//IntervalTimer myTimerLoopNetwork;

void setup() {
  Ethernet.begin(mac,ip);
  myUDP.begin(NET_PORT);
//  Ethernet._fnet_poll.end(); // Note : poll is useless in my case and i wanted to know if it changes something or not (sadly it changes nothing)
//  myTimerLoopNetwork.begin(loopNetwork, 100);
}

void loop() {
  loopNetwork();
  delay(100);
}

//bool isLoopNetwork=false;
void loopNetwork(){
//  if(isLoopNetwork) return;
//  isLoopNetwork=true;
  packetSize = myUDP.parsePacket();
  if (packetSize){
//      isLoopNetwork=false;
      myUDP.read(netPacket, packetSize);
      Serial.print((char)(netPacket[0]));
      Serial.println(" test_for_freeze");
  }
//  isLoopNetwork=false;
}

WebServer: Your connection was interrupted

Hello, I have my Teensy board and am trying my hand at Ethernet. Unfortunately I can not get the "WebServer.ino" example to work. Is there anything to consider with this example, or is it enough to flash the program and plug in the Ethernet cable? When I try this, I get in my browser unfortunately only an error.

/*
  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 <NativeEthernet.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, 1, 177);

// 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
  }
  Serial.println("Ethernet WebServer Example");

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

  // 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(1);
    // close the connection:
    client.stop();
    Serial.println("client disconnected");
  }
}

EthernetClient::flush() seems to cause a hang

I often like to call flush() before calling close() (In this case, it's stop()), however, EthernetClient::flush() seems to hang. To work around this, I'm just calling stop() without the flush().

How to set mac and ip address to run UDPSendReceiveString example

I am new to UDP communication and I was trying to run UDPSendReceiveString.ino example but I dont know how to find my local network ethernet ip and mac. On linux I tried config -a and ip a which give me enp0s31f6 (I understand this represent the ethernet) but I there is no IP address and I dont know how to paste my MAC address in the form 4c:...:2e to the template below:

byte mac[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};

UDP read() doesn't work in conjunction with the Arduino String library

Following code doesn't work with the Native Ethernet library.
The code works with STM32duino with LWIP and with the WIZNet library

#include "Arduino.h"
#include <TeensyID.h>
#include <NativeEthernet.h>
#include <NativeEthernetUdp.h>

uint8_t mac[6];
IPAddress localIP(10, 101, 1, 201);
IPAddress subnet(255, 255, 0, 0);
uint16_t localPort = 8001;
IPAddress remoteIP(10, 101, 1, 100);
uint16_t remotePort = 8000;

EthernetUDP udp;

void setup() {
	teensyMAC(mac);
	Serial.begin(9600);
	Ethernet.begin(mac, localIP);
	udp.begin(localPort);
	}

void loop() {
	String message;
	int size;
        size = udp.parsePacket();
	if (size > 0) {
		// Fill the msg with all of the available bytes
	                while (size--) {
			message += (char)(udp.read());
			}
                Serial.println(message);
		message = String();
		}
	}

The application stop working when reaching message += (char)(udp.read());
If using the standard C++ string library it works as expected. Also when using a char buffer array.
This example works

#include "Arduino.h"
#include <TeensyID.h>
#include <NativeEthernet.h>
#include <NativeEthernetUdp.h>
#include <string>

using namespace std;

uint8_t mac[6];
IPAddress localIP(10, 101, 1, 201);
IPAddress subnet(255, 255, 0, 0);
uint16_t localPort = 8001;
IPAddress remoteIP(10, 101, 1, 100);
uint16_t remotePort = 8000;

EthernetUDP udp;

void setup() {
	teensyMAC(mac);
	Serial.begin(9600);
	Ethernet.begin(mac, localIP);
	udp.begin(localPort);
	}

void loop() {
	string message;
	int size;
        size = udp.parsePacket();
	if (size > 0) {
		// Fill the msg with all of the available bytes
	                while (size--) {
			message += (char)(udp.read());
			}
                Serial.println(message.c_str());
		message.erase();
		}
	}

Enabling mDNS causes hang, then reboot of Teensy 4.1

I'm putting together a device that reads two ADCs (simultaneous sampling) and sends the values over TouchOSC. I originally had all the networking stuff worked out on the esp32, but switched to the Teensy because of more flexible SPI hardware, plus availability of the esp32 boards with onboard ethernet wasn't great so it looked like getting them wouldn't meet my deadline.

I stripped my original code down to the bare minimum.

#include <NativeEthernet.h>
//#include <NativeEthernetUdp.h>

// Extract the hardware MAC from uC itself, and stuff it into an array
uint8_t mac[6];
void teensyMAC(uint8_t *mac) {
    for(uint8_t by=0; by<2; by++) mac[by]=(HW_OCOTP_MAC1 >> ((1-by)*8)) & 0xFF;
    for(uint8_t by=0; by<4; by++) mac[by+2]=(HW_OCOTP_MAC0 >> ((3-by)*8)) & 0xFF;
    Serial.printf("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}

// Mirror the enum EthernetHardwareStatus in NativeEthernet.h so we can print a human readable value.
// Shouldn't this enum be updated to have a 'NativeEthernet" value?
char HWStatus[][14] = {"EthNoHardware",
                     "EthernetW5100",
                     "EthernetW5200",
                     "EthernetW5500"};

//// buffers for receiving and sending data. Currently unused.
//char packetBuffer[UDP_TX_PACKET_MAX_SIZE];  // buffer to hold incoming packet,
//char ReplyBuffer[] = "acknowledged";        // a string to send back
//
//// An EthernetUDP instance to let us send and receive packets over UDP
//EthernetUDP udp;
//
////IP address to send UDP data to:
//const char * udpAddress = "192.168.1.50";
const int udpPort = 8000;
//
//// Not connected yet!
//boolean connected = false;

int ledPin = 13;
int value = 0;

void setup(void) {

  Serial.begin(115200);

  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);

  Ethernet.setStackHeap(1024 * 64);
  Ethernet.setSocketSize(1024 * 16);
  Ethernet.setSocketNum(1);

  teensyMAC(mac);
  Ethernet.begin(mac);

  Serial.print("IP  address: ");
  Serial.println(Ethernet.localIP());
  Serial.send_now();
  Serial.println(HWStatus[Ethernet.hardwareStatus()]);
  Serial.send_now();

//  This sketch will run indefinitely with mDNS commented out, hangs then reboots when enabled.
  MDNS.begin("Teensy41", 1); //.local Domain name and number of services
  MDNS.setServiceName("Teensy41_OSC"); //Uncomment to change service name
  MDNS.addService("_osc._udp", udpPort); 

}

void loop(void) {
  // Count loop iterations, toggle LED and print value every 10 million loops as an alternative to blocking with delay()
  if((value % 10000000) == 0) {
    digitalWrite(ledPin, !digitalRead(ledPin));
    Serial.print("Loop:  ");
    Serial.println(value / 10000000);
    Serial.send_now();
    fnet_service_poll();  // Is this even necessary to call by the user? Ideally, the ethernet library should
                          // run a timer to automatically execute housekeeping tasks. Is this already done?
                          // It didn't seem to make a difference when the mDNS service was enabled.
    if (value >= 1000000000 ) value = 0;
  }

  value++;
}

The number of iterations before the hang varies, and occasionally it won't reboot at all, requiring manual intervention.

connect() hangs system when client not available

In the setup() I want to connect to a MQTT broker, this works fine when the broker is online but fails when the broker is not online. I expected that the connect() function returns a false when it cannot connect but instead the system does not get anything back and freezes...

bool connectMQTT()
{
  EthernetClient testcl;
  char sIp[15] = "192.168.2.44";
  IPAddress MQTTbrokerIP = parseIP(sIp);
  if(testcl.connect(MQTTbrokerIP, settingMQTTport)){
    return true;
  else{
    return false;
}

Memory leak in EthernetMDNS

I noticed that there is a memory leak in EthernetMDNS: in its begin() function it allocates memory on the heap of the service descriptors (service_desc) which is never freed. I might run into the case where I am calling EthernetMDNS::begin() multiple times (each time the ethernet cable is re-plugged) and then would have a memory leak.

I am willing to prepare a patch which just removes the service_desc alltogether since it never seems to be used anyways. Would you be interested?

400 Bad Request while posting to InfluxDB

Hi,

For a project we are trying to monitor a status protocol sent on local network over TCP and post these status messages over HTTPS to a InfluxDB instance on AWS at https://www.influxdata.com/products/influxdb-cloud/.

Posting a string to a test instance over LAN to a IP works fine, but whenever we try to post to the AWS subdomain we are greeted with this response:
HTTP/1.1 400 Bad Request
Server: awselb/2.0
Date: Mon, 27 Sep 2021 18:13:02 GMT
Content-Type: text/html
Content-Length: 122
Connection: close

<title>400 Bad Request</title>

400 Bad Request

Since we verified the headers and body of the post are correct when we post locally, and posting to AWS works when using Postman, we are at a loss at the moment. Unfortunately I have no information about the configuration of the server we try to POST to.

As a test we set-up the WebClientRepeatingTLS example using our own POST headers and body.

#include <NativeEthernet.h>

uint8_t mac[6];
void teensyMAC(uint8_t *mac) {
  for (uint8_t by = 0; by < 2; by++) mac[by] = (HW_OCOTP_MAC1 >> ((1 - by) * 8)) & 0xFF;
  for (uint8_t by = 0; by < 4; by++) mac[by + 2] = (HW_OCOTP_MAC0 >> ((3 - by) * 8)) & 0xFF;
  Serial.printf("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}

// initialize the library instance:
EthernetClient client;
const int port = 443;

char server[] = "influxdata.com";  

//IPAddress server(192, 168, 1, 246);

String outputMSG = "measurementName,tagKey=tagValue fieldKey=1i";
unsigned long lastConnectionTime = 0;           // last time you connected to the server, in milliseconds
const unsigned long postingInterval = 5 * 1000; // delay between updates, in milliseconds

void setup() {
  teensyMAC(mac);
  Serial.begin(9600);
  while (!Serial) {
    ; 
  }

  Serial.println("Initialize Ethernet with DHCP:");
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    if (Ethernet.hardwareStatus() == EthernetNoHardware) {
      Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
      while (true) {
        delay(1);
      }
    }
    if (Ethernet.linkStatus() == LinkOFF) {
      Serial.println("Ethernet cable is not connected.");
    }
  } else {
    Serial.print("  DHCP assigned IP ");
    Serial.println(Ethernet.localIP());
  }
  delay(1000);
}

void loop() {
  if (client.available()) {
    char c = client.read();
    Serial.write(c);
  }
  if (millis() - lastConnectionTime > postingInterval) {
    httpRequest();
  }

}

void httpRequest() {
  client.stop();
  Serial.print("Content-Length: ");
  Serial.println(outputMSG.length());
  Serial.println("");

  if (client.connect(server, port, true)) { 
    Serial.println("connecting to ");
    Serial.print(server);
    Serial.print(":");
    Serial.println(port);

        client.println("POST /api/v2/write?org=ORG_HERE&bucket=BUCKET_HERE&precision=s HTTP/1.1");
        client.println("Host: https://eu-central-1-1.aws.cloud2.influxdata.com");
        client.println("Authorization: Token <<TOKEN HERE>>");
        client.println("Content-Type: text/plain");
        client.print("Content-Length: ");
        client.println(outputMSG.length());
        client.println("Accept-Encoding: gzip, deflate, br");
        client.println("Connection: keep-alive");
        client.println();
        client.println(outputMSG);
        client.println();
        
    lastConnectionTime = millis();
  } else {
    Serial.println("connection failed");
  }

Could anyone help us understand why the post to aws is not going through?

Cheers,
Boy

Code works then when restarting, it picks IP 0.0.0.0

I have a Teensy 4.1 sketch which uses the NativeEternet library. I am using the latest versions of TeensyDuino and NativeEthernet.

My program gets a static IP and runs without ANY problems. The program uses the watchdog to restart every 48 hours. And often it restarts and everything works well.

  1. Every once in a while, the Teensy cannot be reached on the net.

  2. When this happens and the Teensy restarts, it picks a "0.0.0.0" IP

Normally, when the board is not connected to the network, the code blocks and it never gets a static IP. So I do not know how it returns with IP = 0.0.0.0 ?

  1. Disconnecting power and reconnecting does NOT solve the problem.

  2. Leaving the board disconnected for a minute or so somehow fixes the issue and everything goes back to working normally.

Is this a hardware or a software problem?

Thanks.

Teensy 4.1 MQTT

I cannot get this library to work with the Pubsubclient library to connect to MQTT over ethernet. I used the example from pubsubclient and replace Ethernet.h with NativeEthernet.h. Is there anything more I need to do?
Other Ethernet functionality works ๐Ÿ˜•

EthernetClient connect does not read data after a previous client is closed (but it can write)

In a scenario where I am handling a reconnect after the server restarts, I am starting a new client as follows:

EthernetClient client = EthernetClient();

client.connect(ip, port);

FDOS_LOG.printf("Ethernet client connect:%d\n", client.connected());

While this works perfectly the first time, the second time this client will never have bytes available() for reading. It does write properly (the remote server sees the data). Similar code works fine with the WifiClient (esp32 implementation).

Before creating the new client, I am calling .stop on the previous one.

Server.avaiable() randomly stalls the MCU for X-seconds

when connecting top the server using a browser, it works fine untill it suddenly grinds to a halt and stops updating. After some searching, it seems the server halts for a while and then it starts running again. This behaviour results in lots of timeout errors

`
byte mac[] = {0x04, 0xe9, 0xe5, 0x0d, 0xd6, 0x4b};
IPAddress ip(10, 116, 114, 134); // IP address, may need to change depending on network

EthernetServer server(80); // create a server at port 80
EthernetClient client;
char HTTP_req[REQ_BUF_SZ] = {0}; // buffered HTTP request stored as null terminated string
char req_index = 0; // index into HTTP_req buffer
uint32_t ethping = 0;
String loc = "loop";

void ethernet_init() {
// start the Ethernet connection and the server:
Ethernet.begin(mac); // DHCP
//Ethernet.begin(mac,ip); // Static IP

// Check for Ethernet hardware present
if (Ethernet.hardwareStatus() == EthernetNoHardware) {
if (Serial)Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :(");
error_blink(ETHERNET_NO_HARDWARE);
do {
if (Serial)Serial.println("Please connect Ethernet shield");
error_blink();// do nothing, no point running without Ethernet hardware
}
while (Ethernet.hardwareStatus() == EthernetNoHardware);
error_blink(PULSE);
}
if (Ethernet.linkStatus() != LinkON) {
if (Serial)Serial.println("Ethernet cable is not connected.");
error_blink(ETHERNET_NO_CABLE);
do {
if (Serial)Serial.println("Please connect Ethernet cable");
error_blink();// do nothing, no point running without Ethernet cable
}
while (Ethernet.hardwareStatus() == LinkOFF);
error_blink(PULSE);
}

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

void ethernet_client() {
client = server.available(); // try to get client

if (client) { // got client?
boolean currentLineIsBlank = true;
if (Serial) Serial.println("Client");
while (client.connected()) {
loc = "ethc";
can0.events();
error_blink();
if (client.available()) { // client data available to read
char c = client.read(); // read 1 byte (character) from client
// limit the size of the stored received HTTP request
// buffer first part of HTTP request in HTTP_req array (string)
// leave last element in array as 0 to null terminate string (REQ_BUF_SZ - 1)
if (req_index < (REQ_BUF_SZ - 1)) {
HTTP_req[req_index] = c; // save HTTP request character
req_index++;
}
// last line of client request is blank and ends with \n
// respond to client only after last line received
if (c == '\n' && currentLineIsBlank) {
if (Serial) Serial.println("XML request");
loc = "ethx";
// send a standard http response header
client.println("HTTP/1.1 200 OK");
// remainder of header follows below, depending on if
// web page or XML page is requested
// Ajax request - send XML file
if (strstr(HTTP_req, "HVPC_inputs")) {
// send rest of HTTP header
client.println("Content-Type: text/xml");
client.println("Connection: keep-alive");
client.println();
Settings();
// send XML file containing input states
XML_response(client);
}
else { // web page request
if (Serial) Serial.println("Page request");
// send rest of HTTP header
client.println("Content-Type: text/html");
client.println("Connection: keep-alive");
client.println();
// send web page
File webFile = SD.open("index.htm"); // open web page file
if (webFile) {
error_blink(SENDING_FILE);
loc = "ethf";
char file_buffer[ETH_BUFFER_SIZE];
int avail;
while (avail = webFile.available()) {
int to_read = min(avail, ETH_BUFFER_SIZE);
if (to_read != webFile.read(file_buffer, to_read)) {
break;
}
client.write(file_buffer, to_read);
}
webFile.close();
error_blink(PULSE);
}
}
// display received HTTP request on serial port
if (Serial) Serial.println(HTTP_req);
// reset buffer index and all buffer elements to 0
req_index = 0;
StrClear(HTTP_req, REQ_BUF_SZ);
if (Serial) Serial.println("cleared");
break;
}
// every line of text received from the client ends with \r\n
if (c == '\n') {
// last character on line of received text
// starting new line with next character read
currentLineIsBlank = true;
}
else if (c != '\r') {
// a text character was received from client
currentLineIsBlank = false;
}
} // end if (client.available())
} // end while (client.connected())
delay(1); // give the web browser time to receive the data
client.stop(); // close the connection
client = 0;
Ethernet.maintain();
if (Serial)
{
Serial.println("Client stopped");
Serial.println();
Serial.print("server is at ");
Serial.println(Ethernet.localIP());
}
}
}
`

Data Access Violations

Hi!

In the FNET-TCP stack. In the file "fnet_tcp.c" in the function: "static fnet_bool_t _fnet_tcp_add_inpbuf( fnet_socket_if_t *sk, fnet_netbuf_t *insegment, fnet_flag_t *ackparam )", there are two lines which often cause Nullpointer exceptions...

/* If the temporary buffer received the lost segment
* move the data from the temporary buffer to the input buffer of the socket.*/

Line 1: if(FNET_TCP_COMP_GE(seq, fnet_ntohl(FNET_TCP_SEQ(cb->tcpcb_rcvchain)))) => Data Access Violation

Line 2: cb->tcpcb_count -= cb->tcpcb_rcvchain->total_length; => Data Access Violation

I tried the code without the whole "lost segment"-part and the lock-ups are gone, BUT: after a certain time... (after a few hours) i don't receive data anymore and no client can connect to the teensy anymore...

Sorry for my bad english,

Anyways thanks for your awesome library... it would be nice if this could be fixed, because otherwise it's all perfect for me! :)

Please add example for TLS rootCa verification

First: Thank you very much for your excellent work!
Board: Teensy 4.1
IDE: Platformio
Latest version of NativeEthernet library

I successfully followed the example 'WebClientRepeatingTLS' and could read from the page 'pjrc.com/about/contact.html'.
However I was not successful to get rootCa verification working. Is it supported?
I downloaded the root certificate DST Root CA X3 in the base64 encoded form from pjrc.com.

const char *dst_root_ca =
"-----BEGIN CERTIFICATE-----\n"
"MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/\n"
"MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\n"
"DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow\n"
"PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD\n"
"Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n"
"AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O\n"
"rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq\n"
"OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b\n"
"xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw\n"
"7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD\n"
"aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV\n"
"HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG\n"
"SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69\n"
"ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr\n"
"AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz\n"
"R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5\n"
"JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo\n"
"Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ\n"
"-----END CERTIFICATE-----";

and entered the certificate through:

 client.setCACert((char *)dst_root_ca, strlen(dst_root_ca));

But I got error messages:

Initialize Ethernet with DHCP:
DHCP assigned IP 192.168.1.102
You're connected to the network, IP = 192.168.1.102
TLS ca certificate error.
connecting...
HTTP/1.1 400 Bad Request
Date: Sun, 14 Mar 2021 18:10:08 GMT
Server: Apache/2.4.18 (Ubuntu)
Strict-Transport-Security: max-age=15552000
Cache-Control: stale-while-revalidate=30
Content-Length: 441
Connection: close
Content-Type: text/html; charset=iso-8859-1

<title>400 Bad Request</title>

Bad Request

Your browser sent a request that this server could not understand.
Reason: You're speaking plain HTTP to an SSL-enabled server port.
Instead use the HTTPS scheme to access this URL, please.


Apache/2.4.18 (Ubuntu) Server at www.pjrc.com Port 443 SockIndex: 0 SockStatus: 17 RecvErr: -26 SockIndex: 0 SockStatus: 17 RecvErr: -26 ...... ...... ...... Thanks in advance

EthernetClient::read(buf, size) always seems to return size

This function always seems to return the size value, no matter what I pass in. If nothing's available, or something less than size is available, it should return that number.

Is this function even intended to be called without first checking "socket-available" or some such, and then using that value for size?

Udp.parsePacket() is slow

How fast can I expect Udp.parsePacket() to be? In this example code, I am parsing UDP packets and toggling a GPIO pin to see how fast the code runs IRL. The parsing takes 330nS. I expected (based on the clock speeds and the 100MBps interface) the speeds to be orders of magnitude higher... 330ns is around 550 clock cycles. I just want to know if there is something I can do to improve this or that the library is focused on compatibility, not performance. Thanks!

#include <NativeEthernet.h>

byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192, 168, 1, 177);
unsigned int localPort = 6454;      // local port to listen on

// buffers for receiving and sending data
#define UDP_TX_PACKET_MAX_SIZE 1480
unsigned char packetBuffer[UDP_TX_PACKET_MAX_SIZE];  // buffer to hold incoming packet,
char ReplyBuffer[] = "acknowledged";        // a string to send back

// An EthernetUDP instance to let us send and receive packets over UDP
EthernetUDP Udp;

const int PIN_0 = 38;
int packetSize = 0;

void setup() {
//  noInterrupts();
  teensyMAC(mac);
  pinMode(PIN_0, OUTPUT);
  Ethernet.begin(mac, ip);
  Udp.begin(localPort);
}

void loop() {

  while (1) {
    digitalToggleFast(PIN_0);
    //delayNanoseconds(1);

    packetSize = Udp.parsePacket();
    if (packetSize) {
      Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
    }
  }
}

/*********************** teensyMAC *********************/
void teensyMAC(uint8_t *mac)
{
  for (uint8_t by = 0; by < 2; by++) mac[by] = (HW_OCOTP_MAC1 >> ((1 - by) * 8)) & 0xFF;
  for (uint8_t by = 0; by < 4; by++) mac[by + 2] = (HW_OCOTP_MAC0 >> ((3 - by) * 8)) & 0xFF;
}

reading client.available() takes long from time to time - Teensy 4.1

I have so far used Arduino Mega2560 and Arduino Due + Ethernet shield when accessing devices on my local network. This worked well, but the performance of Teensy 4.1 is so much higher that I started to port some of my programs. Some of my programs read information from two Philips Hue Bridges. Scanning any of these two devices usually takes less than 50us (Teensy 4.1) but approx. once per hour (there is no fixed frequency to the event) Teensy's NativeEthernet reading of client.available()) take approx. 1700ms which is far too long for the rest of my program. I would rather like to interrupt these rare long processing or preferably like to start processing an incoming data stream whilst it is being received.

Therefore on Arduino Due I always put whilst( !client.available() && timeNow < maxTime) in front of the processing, which gave me the smallest wait time between if(client.connect(server,port)) and the begin of the processing or broke the processes after a given (too long waiting) time.

The following cut out of a test program shows the issue with client.available() in depth

unsigned long A_NOW=millis();
unsigned long StopWait=A_NOW+WaitTime;

                 while(StopWait > millis())
                 {
                    delayMicroseconds(10);
                    if(client.available()>0) {Serial.print("\tc.avail: "); Serial.print(client.available()); break;}
                                    
                 }

                 unsigned long B_NOW=millis();
                               
                 if(B_NOW-A_NOW > 25)
                 { 
                   Serial.print("\n\tLONG wait: B_NO-A_NOW="); Serial.println(B_NOW-A_NOW); 
                   Serial.print(" WaitTime:"); Serial.println(WaitTime);
                   Serial.print(" StopWait:"); Serial.println(StopWait); 
                   Serial.print("  A_NOW:"); Serial.println(A_NOW); 
                   Serial.print("  B_NOW:"); Serial.println(B_NOW); 
                   Serial.print("  millis:"); Serial.println(millis());                      
                 
                   Serial.print("\tclient.available(): "); Serial.print(client.available()); 
                 }

The USB Serial output reads

c.avail: 2048
    LONG wait: B_NO-A_NOW=1789 
    WaitTime:100 
    StopWait:95247  
    A_NOW:95147
    B_NOW:96936  millis:96936
client.available(): 2048	

I have also tried !client.available(), elapsedMillis && elapsedMicros and it produces the same behaviour. I successfully used Arduino Due so far and never saw such behaviour (but reading the HueBridge took far longer).
The process is not interrupted by any ISR and is not part of an ISR.

Is there anything I can do or is there anything I am doing wrong?

Connection timeout and reset problems with the WebServer example

First of all thanks for your hard work!

When I run the basic WebServer example I start to get connection timeouts and resets if I push server even a bit.

I'm using Apache Benchmark to generate the load: ab -k -c 1 -n 20 http://192.168.1.177/

If I keep the -n small things work as expected. With values bigger than 100 I will most of the time get either a connection reset from the server with apr_socket_recv: Connection reset by peer (54) or the client times out after a while apr_pollset_poll: The timeout specified has expired (70007). When the Apache Benchmark is waiting for the response that never comes but has not timed out yet the website loads just fine I create a new connection for example using a browser.

I have tested pretty much the same code with Arduino Uno and the ESP8266 and ESP32 chips and I see no problems. This is why expect the problem not to be in my test setup. I also just updated the lib to the latest master. I also have the latest version of your FNET fork. My Teensyduino version is 1.5.3. I can also reproduce the same behaviour with other load testing tools. I have not tried another computer, network or ethernet chip or Teensy.

Adding client.close() before client.stop() did not improve the situation.

Have a nice weekend!

SetSocketSize seems to be circumvented

Code such as this silently fails to change the recv buf size, and incoming packets never arrive

// start UDP
Ethernet.setSocketSize(1620 * 3);
Udp.begin(T_PORT);

I looked at the code and found this:

void EthernetClass::setSocketSize(size_t _socket_size)
{
if(socket_size != 0) return;
socket_size = _socket_size;
}

This effectively disallows setting of the size unless the size is zero. No idea who sets the initial value, but it isn't zero when I call setSocketSize, and so my call has no effect. I doubt that is what was intended, but please let me know if I am missing something here. I changed the code to this:

void EthernetClass::setSocketSize(size_t _socket_size)
{
//if(socket_size != 0) return;
socket_size = _socket_size;
}

And now all is working fine for me. I think what you want here is something like (NOTE: I do not know where the actual max packet size is to be found. I just used a made up symbol MAX_MTU here...)

void EthernetClass::setSocketSize(size_t _socket_size)
{
if(_socket_size > MAX_MTU) _socket_size = MAX_MTU;
socket_size = _socket_size;
}

I found this:

#define UDP_TX_PACKET_MAX_SIZE 2048

but it is never used. In any case, I think programs should be allowed to set the recv buf size up to the actual limit of the physical transport, whatever that might be...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.