Skip to content
This repository has been archived by the owner on Feb 4, 2023. It is now read-only.

Spiffs not work #2

Closed
workpage2 opened this issue Apr 13, 2020 · 40 comments
Closed

Spiffs not work #2

workpage2 opened this issue Apr 13, 2020 · 40 comments

Comments

@workpage2
Copy link

workpage2 commented Apr 13, 2020

I am using esp32 + w5500. The output of the index.html file to the web site via spiffs does not work. Simple helloserver works. I used this construction in standard webserver.h + esp32 via WiFi. Everything works. Plz help.

#include <FS.h>  // Библиотека для работы с файловой системой
#include <SPIFFS.h>
#include <SPI.h>
#include <Ethernet.h>
bool tcp_session = false;
bool EthernetUsable = false;  // W5500 found??

#define W5500_RST_PORT   21
byte mac[] = {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
#define EthernetLinkUP_Retries  10  //

#include <EthernetWebServer.h>
EthernetWebServer HTTP(80);

void setup() 
{

Serial.begin(115200);                                                   // Инициализируем вывод данных на серийный порт со скоростью 9600 бод
  SPIFFS.begin();                                                       // Инициализируем работу с файловой системой                          

Serial.println("Used/default ESP32 pinout:");
Serial.print("MOSI:");
Serial.println(MOSI);
Serial.print("MISO:");
Serial.println(MISO);
Serial.print("SCK:");
Serial.println(SCK);
Serial.print("SS:");
Serial.println(SS);
//  Serial.println(RST);
Serial.print("Reset:");
Serial.println(W5500_RST_PORT);

SPI.begin();

Serial.println("Resetting WizNet for consistent results");
pinMode(W5500_RST_PORT, OUTPUT);
digitalWrite(W5500_RST_PORT, LOW);
delayMicroseconds(500);
digitalWrite(W5500_RST_PORT, HIGH);
delayMicroseconds(1000);

Ethernet.init(SS);

Serial.println("Starting ethernet");
Ethernet.begin(mac);
//Ethernet.begin(mac,ip);
//delay(1000);
vTaskDelay(1000 / portTICK_RATE_MS);

switch (Ethernet.hardwareStatus()) {
case EthernetNoHardware:
  Serial.println("Ethernet Hardware was not found, can't continue...");
  EthernetUsable = false;
  break;
case EthernetW5100:
  Serial.println("W5100 hardware found");
  EthernetUsable = true;
  break;
case EthernetW5200:
  Serial.println("W5200 hardware found");
  EthernetUsable = true;
  break;
case EthernetW5500:
  Serial.println("W5500 hardware found");
  EthernetUsable = true;
  break;
default:
  Serial.print("Undefined hardware found:");
  Serial.println(Ethernet.hardwareStatus());
  Serial.print("No Hardware value::");
  Serial.println(EthernetNoHardware);
  EthernetUsable = false;  // not acceptable

  break;
}

int retries = 0;
do {
//delay(500);
vTaskDelay(500 / portTICK_RATE_MS);

switch (Ethernet.linkStatus()) {
  case Unknown:
    Serial.println("Unknown link status");
    EthernetUsable = false;
    break;
  case LinkOFF:
    Serial.println("LinkOFF");
    EthernetUsable = false;
    break;
  case LinkON:
    Serial.println("LinkON");
    EthernetUsable = true;
    break;
  default:
    EthernetUsable = false;
    Serial.println("Undefined link status");
}
} while ( (Ethernet.linkStatus() != LinkON ) && retries++ < EthernetLinkUP_Retries );


if (EthernetUsable == true) {
// https://www.pjrc.com/arduino-ethernet-library-2-0-0/
Serial.print("LocalIP:");
Serial.println(Ethernet.localIP());

Serial.print("GW:");
Serial.println(Ethernet.gatewayIP());

Serial.print("Subnet Netmask:");
Serial.println(Ethernet.subnetMask());

Serial.print("DNS Server IP:");
Serial.println(Ethernet.dnsServerIP());

//Serial.print("MAC:");
//Serial.println(Ethernet.MACAddress());

}

HTTP.begin();

HTTP.on("/", [](){                                        
if(!handleFileRead(HTTP.uri()))                                       // Если функция handleFileRead (описана ниже) возвращает значение false в ответ на поиск файла в файловой системе
  HTTP.send(404, "text/plain", "Not Found");                        // возвращаем на запрос текстовое сообщение "File isn't found" с кодом 404 (не найдено)                  
});

HTTP.on("/index.html", [](){                                        
if(!handleFileRead(HTTP.uri()))                                       // Если функция handleFileRead (описана ниже) возвращает значение false в ответ на поиск файла в файловой системе
  HTTP.send(404, "text/plain", "Not Found");                        // возвращаем на запрос текстовое сообщение "File isn't found" с кодом 404 (не найдено)                  
});

HTTP.onNotFound([](){                                                 // Описываем действия при событии "Не найдено"
if(!handleFileRead(HTTP.uri()))                                       // Если функция handleFileRead (описана ниже) возвращает значение false в ответ на поиск файла в файловой системе
  HTTP.send(404, "text/plain", "Not Found");                        // возвращаем на запрос текстовое сообщение "File isn't found" с кодом 404 (не найдено)
});

}

void loop() {
HTTP.handleClient();  
}

bool handleFileRead(String path){                                       // Функция работы с файловой системой

//Serial.println(HTTP.uri());
if(path.endsWith("/")) path += "index.html";                          // Если устройство вызывается по корневому адресу, то должен вызываться файл index.html (добавляем его в конец адреса)
if(path.endsWith("/genaset")) path += ".html";
if(path.endsWith("/networksetting")) path += ".html";
String contentType = getContentType(path);                            // С помощью функции getContentType (описана ниже) определяем по типу файла (в адресе обращения) какой заголовок необходимо возвращать по его вызову
if(SPIFFS.exists(path)){                                              // Если в файловой системе существует файл по адресу обращения
File file = SPIFFS.open(path, "r");                                 //  Открываем файл для чтения
Serial.print("path=");
Serial.println(path);
Serial.print("filename=");
Serial.println(file.size());
Serial.print("content=");
Serial.println(contentType);
size_t sent = HTTP.streamFile(file, contentType);                   //  Выводим содержимое файла по HTTP, указывая заголовок типа содержимого contentType
file.close();                                                       //  Закрываем файл
return true;                                                        //  Завершаем выполнение функции, возвращая результатом ее исполнения true (истина)
}
return false;                                                         // Завершаем выполнение функции, возвращая результатом ее исполнения false (если не обработалось предыдущее условие)
}

String getContentType(String filename){                                 // Функция, возвращающая необходимый заголовок типа содержимого в зависимости от расширения файла
  if (filename.endsWith(".html")) return "text/html";                   // Если файл заканчивается на ".html", то возвращаем заголовок "text/html" и завершаем выполнение функции
  else if (filename.endsWith(".css")) return "text/css";                // Если файл заканчивается на ".css", то возвращаем заголовок "text/css" и завершаем выполнение функции
  else if (filename.endsWith(".js")) return "application/javascript";   // Если файл заканчивается на ".js", то возвращаем заголовок "application/javascript" и завершаем выполнение функции
  else if (filename.endsWith(".png")) return "image/png";               // Если файл заканчивается на ".png", то возвращаем заголовок "image/png" и завершаем выполнение функции
  else if (filename.endsWith(".jpg")) return "image/jpeg";              // Если файл заканчивается на ".jpg", то возвращаем заголовок "image/jpg" и завершаем выполнение функции
  else if (filename.endsWith(".gif")) return "image/gif";               // Если файл заканчивается на ".gif", то возвращаем заголовок "image/gif" и завершаем выполнение функции
  else if (filename.endsWith(".ico")) return "image/x-icon";            // Если файл заканчивается на ".ico", то возвращаем заголовок "image/x-icon" и завершаем выполнение функции
  return "text/plain";                                                  // Если ни один из типов файла не совпал, то считаем что содержимое файла текстовое, отдаем соответствующий заголовок и завершаем выполнение функции
}
@khoih-prog
Copy link
Owner

Hi,
The library is currently not intended and tested for ESP8266 and ESP32 as we normally use the their built-in WiFi features. And the issue also has nothing to do with this library.

  1. Your issue can be conflicts between the Ethernet driver (using SPI) and SPIFFS (also using SPI). To verify this, you can start with the simplest code using both Ethernet and SPIFFS.
    If there is still problem, you can try these:
  • Disable Ethernet by using Ethernet CS/SS whenever accessing SPIFFS
  • If issue persists, open issue in related Ethernet library or ESP32/ESP8266
  1. Use EEPROM if you still can not solve the issue.

  2. You can have a look at ESP_FSWebServer to see SPIFFS and ESP32 are working very well together.

Sorry for not being able to help anymore as I'm so busy now. I'll definitely will have a look whenever I have time. Please post the result of your findings.

Regards,

@workpage2
Copy link
Author

workpage2 commented Apr 14, 2020

I made a small modification to check the simultaneous operation of spiffs and ethernet. I am reading a file into a string variable. And I bring to the site in a standard way. It works. Spiffs and ethernet work together. The "streamFile" function in the ethernetwebserver library does not work. At least on esp 32.
This cannot be seen as a permanent solution to the problem. Since the size of the string variable is only 2048 bytes.
You have a very good library, and I would like to use it. But without "streamFile" this is impossible to do.

bool handleFileRead(String path){                                       // Функция работы с файловой системой
  String temp;
  char temp2;
  //Serial.println(HTTP.uri());
  if(path.endsWith("/")) path += "index.html";                          // Если устройство вызывается по корневому адресу, то должен вызываться файл index.html (добавляем его в конец адреса)
  if(path.endsWith("/genaset")) path += ".html";
  if(path.endsWith("/networksetting")) path += ".html";
  String contentType = getContentType(path);                            // С помощью функции 
  getContentType (описана ниже) определяем по типу файла (в адресе обращения) какой заголовок необходимо возвращать по его вызову
  if(SPIFFS.exists(path)){                                              // Если в файловой системе существует файл по адресу обращения
    File file = SPIFFS.open(path, "r");                                 //  Открываем файл для чтения
    Serial.print("path=");
    Serial.println(path);
    Serial.print("filesize=");
    Serial.println(file.size());
    Serial.print("content=");
    Serial.println(contentType);
    while(file.available())
    {
        temp2=file.read();
        //Serial.write(temp2);
        temp=temp+temp2;
    }
    HTTP.send(200, contentType, temp); 
    //size_t sent = HTTP.streamFile(file, contentType);                   //  Выводим содержимое файла по HTTP, указывая заголовок типа содержимого contentType
    file.close();                                                       //  Закрываем файл
    return true;                                                        //  Завершаем выполнение функции, возвращая результатом ее исполнения true (истина)
  }
  return false;                                                         // Завершаем выполнение функции, возвращая результатом ее исполнения false (если не обработалось предыдущее условие)
}

@khoih-prog
Copy link
Owner

That's good news.
How do you connect W5500 to ESP32? Please give the pin-pin connections so that I can reproduce and test.
I'll try to test, find out the root cause and solve the issue to provide support to ESP32/ESP8266 in the very near future. Hopefully everything can be solved.

I already post the code to increase the 2K buffer to 4K/8K/16K in W5x00 in BlynkEthernet_WM: to increase Ethernet buffer.
You can give it a try.

Regards,

@workpage2
Copy link
Author

MOSI:23
MISO:19
SCK:18
SS:5
RESET:21

@workpage2
Copy link
Author

Good day. Any news?

@khoih-prog
Copy link
Owner

Did you try the new Ethernet lib with 2+K buffer fix as in

I already post the code to increase the 2K buffer to 4K/8K/16K in W5x00 in BlynkEthernet_WM: to increase Ethernet buffer.

I send 2+K strings using the modified Ethernet library OK. You can test using the examples in

BlynkEthernet_WM Library

Pls inform if this is OK.

I still haven't worked on your issue with ESP32 yet as the lib is not original made for ESPs. I'll do it soon.

The 2+K string problem can possibly happen because the way you use local var too large (you have to test to be sure if the heap/stack OK). I got similar problem with some boards and solve by moving very long local vars to global.

bool handleFileRead(String path)
{                                       
  // File system function
  String temp;
  ...
}

Try somethng like this to see if it's better

String temp;
bool handleFileRead(String path)
{                                       
   // File system function
  ...
}

@workpage2
Copy link
Author

My webpage is over 60k. Increasing the buffer will not solve the problem. But tomorrow I will definitely try a global variable and write the result here.

@khoih-prog
Copy link
Owner

khoih-prog commented Apr 26, 2020

Also see in my ESP_WiFiManager Library

ESP_FSWebServer example

how to stream large files directly, without reading every byte into String buffer, with FSWebServer.

bool handleFileRead(String path) {
  DBG_OUTPUT_PORT.println("handleFileRead: " + path);
  if (path.endsWith("/")) {
    path += "index.htm";
  }
  String contentType = getContentType(path);
  String pathWithGz = path + ".gz";
  if (filesystem->exists(pathWithGz) || filesystem->exists(path)) {
    if (filesystem->exists(pathWithGz)) {
      path += ".gz";
    }
    File file = filesystem->open(path, "r");
    server.streamFile(file, contentType);
    file.close();
    return true;
  }
  return false;
}

But that is for ESP8266/ESP32WebServer. I still haven't tested with this EthernetServer library to see it's working or not.
You can try this with this EthernetWebServer library
The function prototype and implementation is

template<typename T> size_t streamFile(T &file, const String& contentType);
{
      setContentLength(file.size());
      if (String(file.name()).endsWith(".gz") &&
          contentType != "application/x-gzip" &&
          contentType != "application/octet-stream") {
        sendHeader("Content-Encoding", "gzip");
      }
      send(200, contentType, "");
      return _currentClient.write(file);
}

and use exactly the same to the previous example

EthernetWebServer server(80);
.....
bool handleFileRead(String path) {
  DBG_OUTPUT_PORT.println("handleFileRead: " + path);
  if (path.endsWith("/")) {
    path += "index.htm";
  }
  String contentType = getContentType(path);
  String pathWithGz = path + ".gz";
  if (filesystem->exists(pathWithGz) || filesystem->exists(path)) {
    if (filesystem->exists(pathWithGz)) {
      path += ".gz";
    }
    File file = filesystem->open(path, "r");
    server.streamFile(file, contentType);
    file.close();
    return true;
  }
  return false;
}

@khoih-prog
Copy link
Owner

khoih-prog commented Apr 27, 2020

It seems that ESP32 WebServer has severe bug in handling large file, using either SPIFFS or FFat.
So this is not something relating to Filesystem, I think, but the WebServer and/or other system code.

You can test using ESP32 FSBrowser example using the data in this directory

Test data for ESP_FSWebServer

FS File: /CanadaFlag_1.png, size: 40.25KB
FS File: /CanadaFlag_2.png, size: 8.12KB
FS File: /CanadaFlag_3.jpg, size: 10.89KB

Testing files

You can upload the files to ESP32 filesystem (SPIFFS or FFat) as follows

1. upload the contents of the data folder with MkSPIFFS Tool ("ESP32 Sketch Data Upload" in Tools menu in Arduino IDE) or
2. you can upload the contents of a folder if you change dir into the local folder and run the following command in Ubuntu
$  for file in `ls -A1`; do curl -F "file=@$PWD/$file" esp32fs.local/edit; done

Testing the similar example for ESP8266 is OK with that large file using these examples

  1. ESP_FSWebServer example for ESP8266
  2. ESP8266 FSBrowser example

It's possibly some bugs in ESP32 WebServer / system library code, but I don't have time to follow up with this.

You can open an issue in ESP32 support, mentioned details about your test with

  1. ESP32 FSBrowser example => ESP32 WebServer hangs up

image

  1. ESP8266 FSBrowser example => ESP8266 WebServer displays OK and still survives

image

I'm sorry I can't spend more time on this matter. Please open issue on ESP32, and give me a link / update.

@workpage2
Copy link
Author

I tried using global variables. This also does not work.
I also found this: sirleech/Webduino#69 .
I think there is a conflict on the spi bus. Tell me how to send data from a file one byte or a small packet? That would solve the problem.

@khoih-prog
Copy link
Owner

I already update the version to v1.0.6 to support ESP32 and ESP8266. Your contribution is noted in README by initiating the work on ESP32/ESP8266.

Thanks to Vladimir to initiate the work on ESP32 in Spiffs not work Issue #2

@workpage2
Copy link
Author

I checked the new library 1.0.6
SPIFFS does not work. (streamFile)

@khoih-prog
Copy link
Owner

khoih-prog commented Apr 27, 2020

I don't expect v1.0.6 to work in your case. Just for normal smaller file applications only.

About SPI

image

The SPI bus is designed for 1 master and multiple slaves and you have to check if

  1. The CS/SS are separate for each slave. Did you check if you do correctly?
  2. The SPI driver / firmware are written not fully correctly, not taking care of multiple-slave scenarios or permitting one slave to monopolize the bus => other slaves will be dead while waiting for attention. I'm afraid this is the case.
  3. Hardwarewise, a tri-state chip for MOSI/MISO signals of the SPI slave so you can share the SPI bus with other devices. Whenever the SPI slave is not selected by CS/SS, the slave's MOSI/MISO input/output must be in tri-state mode to avoid interference with SPI communications.

That's why the ESP8266 is working OK with the same hardware / software, while ESP32 can't.

Did you have time to verify the ESP32 and ESP8266 examples in my previous posts

  1. ESP32 FSBrowser example
  2. ESP_FSWebServer example for ESP8266
  3. ESP8266 FSBrowser example

to have some ideas, then post issue on ESP32 so that someone will have a look?

You can also have some easy try with ESP8266 using the same code / W5500 and SPIFFS to see how it handles large files.

@khoih-prog
Copy link
Owner

Hi @workpage2 , @tcpipchip

Good news. I think I find out the problem now.

As you see in

image

Each SPI slave must use a different CS/SS pin, and pin SS in ESP32 has been use by Flash/SPIFFS/EEPROM and defined as SPISS. That's why we have all conflict issues so far. Sending a small piece of data might be OK, but larger data will create SPI bus conflict problem.
Just change the pin to another one. I tested with GPIO13 and OK (many more other pins can be OK as well)

//KH for ESP32
#elif defined(ESP32)
//pin SS already defined in ESP32 as pin 5, don't use this as conflict with SPIFFS, EEPROM, etc.
// Use in GPIO13
#warning w5100.cpp Use ESP32, change SS_PIN_DEFAULT to GPIO13, MOSI(23), MISO(19), SCK(18)
#define SS_PIN_DEFAULT  13    //SS
///////

Please test and inform me the result.

@workpage2
Copy link
Author

I checked "ESP32 FSBrowser example".
It works. But with wifi I had no problems.
I changed CS to 13 pin. Initialization is going well, but data from spiffs does not go to ethernet.
Please check my code on your hardware. At the top of the page.
#2 (comment)

@workpage2
Copy link
Author

Studied esp32 documentation. Internal flash memory is connected by a separate spi interface. Pin 6-11 are involved and in no way connected with the user spi.

@workpage2
Copy link
Author

workpage2 commented May 3, 2020

This code is working correctly. Displays large files in the browser.
But the web page loads slowly. 2-3 seconds. Speak any thoughts.

filename="/index.html";
if(SPIFFS.exists(filename)){                                              // Если в файловой системе существует файл по адресу обращения
  File file = SPIFFS.open(filename, "r");                                 //  Открываем файл для чтения
  Serial.print("filename=");
  Serial.println(filename);
  Serial.print("filesize=");
  Serial.println(file.size());
while(file.available())
{
    temp2=file.read();        
    //Serial.write(temp2);
    temp=temp+temp2;
    fileexit++;
    if (fileexit==950)
      {
        server.print(temp);
        fileexit=0;
        temp="";
      }
  }
file.close();   
}
else temp="File not found";
server.print(temp);

This is the most important piece of code. If you need a complete code - write.

@khoih-prog
Copy link
Owner

If you can post the whole code to save me some time to rewrite, I'll test and hope to see something wrong.

@workpage2
Copy link
Author

Here, two connections are launched simultaneously - wifi and ethernet. Also, two web servers are launched simultaneously. The web server for ethernet only works with the index.html page, which must be uploaded to SPIFFS in advance.

#include <FS.h>  // Библиотека для работы с файловой системой
#include <SPIFFS.h>
#include "SPI.h"
#include "Ethernet.h"
#include "WebServer.h" //This is WebDuino library!!!!!!!!!!!!!!!!!! Standart webserver.h library need erase
//you can download this library from https://github.com/sirleech/Webduino

#define EthernetLinkUP_Retries  10  //
bool tcp_session = false;

#define W5500_RST_PORT   21
byte mac[] = {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
bool EthernetUsable = false;  // W5500 found??

#include <WiFi.h>
const char* ssid = "SSID";
const char* password = "PASS";
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
AsyncWebServer server(80);
const char* PARAM_MESSAGE = "message";

EthernetClient e_client;
WiFiClient w_client;

void notFound(AsyncWebServerRequest *request) {
request->send(404, "text/plain", "Not found");
}

/* CHANGE THIS TO YOUR OWN UNIQUE VALUE.  The MAC number should be
* different from any other devices on your network or you'll have
* problems receiving packets. */
//static uint8_t mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

/* CHANGE THIS TO MATCH YOUR HOST NETWORK.  Most home networks are in
* the 192.168.0.XXX or 192.168.1.XXX subrange.  Pick an address
* that's not in use and isn't going to be automatically allocated by
* DHCP from your router. */
//static uint8_t ip[] = { 192, 168, 1, 210 };

/* This creates an instance of the webserver.  By specifying a prefix
* of "", all pages will be at the root of the server. */
#define PREFIX ""
WebServer webserver(PREFIX, 80);

/* commands are functions that get called by the webserver framework
* they can read any posted data from client, and they output to the
* server to send data back to the web browser. */
void helloCmd(WebServer &server, WebServer::ConnectionType type, char *, bool)
{
  String temp;
  char temp2;
  String filename;
  unsigned int fileexit;
 /* this line sends the standard "we're all OK" headers back to the
 browser */
  server.httpSuccess();

 /* if we're handling a GET or POST, we can output our data here.
 For a HEAD request, we just stop after outputting headers. */
  if (type != WebServer::HEAD)
  {
 /* this defines some HTML text in read-only memory aka PROGMEM.
 * This is needed to avoid having the string copied to our limited
 * amount of RAM. */
 //P(helloMsg) = "<h1>Hello, World! from print</h1>";
 /* this is a special form of print that outputs from PROGMEM */
 //server.printP(helloMsg);

filename="/index.html";
if(SPIFFS.exists(filename)){                                              // Если в файловой системе существует файл по адресу обращения
File file = SPIFFS.open(filename, "r");                                 //  Открываем файл для чтения
Serial.print("filename=");
Serial.println(filename);
Serial.print("filesize=");
Serial.println(file.size());

while(file.available())
{
    temp2=file.read();        
    //Serial.write(temp2);
    temp=temp+temp2;
    fileexit++;
    if (fileexit==950)
      {
        server.print(temp);
        fileexit=0;
        temp="";
      }
}
file.close();   
 }
  else temp="File not found";
    server.print(temp);  
  }
}

void setup()
{
  Serial.begin(115200);
  SPIFFS.begin();    
  
  Serial.println("Used/default ESP32 pinout:");
  Serial.print("MOSI:");
  Serial.println(MOSI);
  Serial.print("MISO:");
  Serial.println(MISO);
  Serial.print("SCK:");
  Serial.println(SCK);
  Serial.print("SS:");
  Serial.println(SS);
  Serial.print("Reset:");
  Serial.println(W5500_RST_PORT);

  SPI.begin();

  Serial.println("Resetting WizNet for consistent results");
  pinMode(W5500_RST_PORT, OUTPUT);
  digitalWrite(W5500_RST_PORT, LOW);
  delayMicroseconds(500);
  digitalWrite(W5500_RST_PORT, HIGH);
  delayMicroseconds(1000);

  // https://www.arduino.cc/en/Reference/EthernetInit
  // 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
   Ethernet.init(SS);    // NOT optional!!!

  Serial.println("Starting ethernet");
  // https://www.arduino.cc/en/Reference/EthernetBegin
  // Ethernet.begin takes about 60 seconds when cable is not connected ...... This is not always acceptable..
  // https://stackoverflow.com/questions/8530102/ethernet-begin-blocks-for-60-seconds-if-theres-no-ethernet-cable
  // DHCP seems to hold a 60 second timeout....
  Ethernet.begin(mac);
  //Ethernet.begin(mac,ip);
 
  //delay(1000);
  vTaskDelay(1000 / portTICK_RATE_MS);
 
  switch (Ethernet.hardwareStatus()) {
      case EthernetNoHardware:
      Serial.println("Ethernet Hardware was not found, can't continue...");
      EthernetUsable = false;
      break;
    case EthernetW5100:
       Serial.println("W5100 hardware found");
      EthernetUsable = true;
      break;
    case EthernetW5200:
      Serial.println("W5200 hardware found");
      EthernetUsable = true;
      break;
    case EthernetW5500:
      Serial.println("W5500 hardware found");
      EthernetUsable = true;
      break;
    default:
      Serial.print("Undefined hardware found:");
      Serial.println(Ethernet.hardwareStatus());

      Serial.print("No Hardware value::");
      Serial.println(EthernetNoHardware);
      EthernetUsable = false;  // not acceptable

      break;
  }

  int retries = 0;
  do {
    //delay(500);
    vTaskDelay(500 / portTICK_RATE_MS);

    switch (Ethernet.linkStatus()) {
      case Unknown:
        Serial.println("Unknown link status");
        EthernetUsable = false;
        break;
      case LinkOFF:
        Serial.println("LinkOFF");
        EthernetUsable = false;
        break;
      case LinkON:
        Serial.println("LinkON");
         EthernetUsable = true;
        break;
      default:
        EthernetUsable = false;
        Serial.println("Undefined link status");
    }
  } while ( (Ethernet.linkStatus() != LinkON ) && retries++ < EthernetLinkUP_Retries );

  if (EthernetUsable == true) {
    // https://www.pjrc.com/arduino-ethernet-library-2-0-0/
    Serial.print("LocalIP:");
    Serial.println(Ethernet.localIP());

    Serial.print("GW:");
    Serial.println(Ethernet.gatewayIP());

    Serial.print("Subnet Netmask:");
    Serial.println(Ethernet.subnetMask());

    Serial.print("DNS Server IP:");
    Serial.println(Ethernet.dnsServerIP());

    //Serial.print("MAC:");
    //Serial.println(Ethernet.MACAddress());

  }

WiFi.mode(WIFI_STA);
  //Esp_wifi_set_ps (WIFI_PS_NONE);
  WiFi.setSleep(false);
  WiFi.begin(ssid, password);
   while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

 server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
         request->send(200, "text/plain", "Hello, world from async");
    });

server.onNotFound(notFound);

    server.begin();
  
  /* initialize the Ethernet adapter */
  //Ethernet.begin(mac, ip);

  /* setup our default command that will be run when the user accesses
   * the root page on the server */
  webserver.setDefaultCommand(&helloCmd);

  /* run the same command if you try to load /index.html, a common
   * default page name */
  webserver.addCommand("index.html", &helloCmd);

  /* start the webserver */
  webserver.begin();
}

void loop()
{
  char buff[64];
  int len = 64;

  /* process incoming connections one at a time forever */
  webserver.processConnection(buff, &len);
}

@workpage2
Copy link
Author

workpage2 commented May 3, 2020

Simple also works

server.print(file.read());

But the speed is still low.

@khoih-prog
Copy link
Owner

Did you try to increase W5500 buffer larger, such as 8K, 16K?

@workpage2
Copy link
Author

No. I use standart buffer.
Can it increase speed?

@workpage2
Copy link
Author

Ideally, you should fix the "streamFile" in the EthernetWebServer library.
This will solve all the problems.

@khoih-prog
Copy link
Owner

khoih-prog commented May 3, 2020

To change, modify w5100.cpp

// Try W5500 next.  Wiznet finally seems to have implemented
	// SPI well with this chip.  It appears to be very resilient,
	// so try it after the fragile W5200
	} else if (isW5500()) {
		CH_BASE_MSB = 0x10;
#ifdef ETHERNET_LARGE_BUFFERS
#if MAX_SOCK_NUM <= 1
		SSIZE = 16384;
#elif MAX_SOCK_NUM <= 2
		SSIZE = 8192;
#elif MAX_SOCK_NUM <= 4
		SSIZE = 4096;
#else
		SSIZE = 2048;
#endif

and Ethernet.h

#if defined(RAMEND) && defined(RAMSTART) && ((RAMEND - RAMSTART) <= 2048)
#define MAX_SOCK_NUM 2      //Reduce MAX_SOCK_NUM to 2 from 4, to increase buffer from 2k to 4K
#else
//#define MAX_SOCK_NUM 4      //Reduce MAX_SOCK_NUM to 4 from 8, to increase buffer from 2k to 4K
#define MAX_SOCK_NUM 1      //Reduce MAX_SOCK_NUM to 1 from 8, to increase buffer from 2k to 16K
#endif

Can it increase speed?

Hope so. But the real issue is possibly somewhere else.
You use only standard ESP32 libraries (WebServer, ESPAsyncWebServer, Ethernet) and have the issue, which has nothing to do with this EthernetWenServer. I'll try to help but also can't spend too much time on this.
I think you'd better raise issue in ESP32 support page to be solved faster.

@workpage2
Copy link
Author

workpage2 commented May 3, 2020

In this case, webserver.h is not an esp32 library. This is the WebDuino library.
https://github.com/sirleech/Webduino
The standard webserver.h library from esp32 is not compatible with other arduino libraries.
WebDuino is considered an obsolete library and is no longer being developed.

@workpage2
Copy link
Author

I still want to use EthernetWebServer, because I consider this the best solution.

@khoih-prog
Copy link
Owner

That's even better to raise ESP32 issue as you can show that standard ESP32 WebServer lib is not working.
Many ESP32-based boards I have here can't have SPIFFS working, as those boards' hardware designers use some pins wrongly and conflict with normal SPIFFS work.
I still suspect that's the case. Can you try with several other ESP32 boards to see.

@khoih-prog
Copy link
Owner

I still want to use EthernetWebServer, because I consider this the best solution.

Glad you see that way. I'll try my best later on to find out why (but it seems very hard to catch), then find a work-around solution.

Did you try using ENC28J60 or LAN8270??

@workpage2
Copy link
Author

I have 28j60 board. I will test it.

@khoih-prog
Copy link
Owner

But I never like ENC and don't think ENC will solve the issue as ENC is much worse (support, ease-of-use, etc.) than W5500. But good to try to see the real reason behind the issue (not W5500, but other libraries)

@tcpipchip
Copy link

tcpipchip commented May 3, 2020 via email

@khoih-prog
Copy link
Owner

ENC28J60 still working fine here!!!!! 24 hours!

But with higher workload / speed (much larger file transfer), I don't know.
I still can see the ENC webpage upload speed slower than W5500, even for small files.

@tcpipchip
Copy link

tcpipchip commented May 3, 2020 via email

@khoih-prog
Copy link
Owner

khoih-prog commented May 4, 2020

@workpage2

OK now, sorry. using this AsyncTCP

@khoih-prog
Copy link
Owner

How do you proceed with your test and know it's running slowly. This is the terminal output and it's running OK so far


Starting ESP32_SPIFFS_Test
FS File: /CanadaFlag_1.png, size: 40.25KB
FS File: /CanadaFlag_2.png, size: 8.12KB
FS File: /CanadaFlag_3.jpg, size: 10.89KB
FS File: /edit.htm.gz, size: 4.02KB
FS File: /favicon.ico, size: 1.12KB
FS File: /graphs.js.gz, size: 1.92KB
FS File: /index.htm, size: 3.63KB
FS File: /wm_config.dat, size: 200B
FS File: /wm_config.bak, size: 200B
FS File: /wm_cred.dat, size: 180B
FS File: /wm_cred.bak, size: 180B
FS File: /wmssl_conf.dat, size: 376B
FS File: /wmssl_conf.bak, size: 376B
FS File: /wmssl_cred.dat, size: 180B
FS File: /wmssl_cred.bak, size: 180B
FS File: /drd.dat, size: 4B

Used/default ESP32 pinout:
MOSI:23
MISO:19
SCK:18
SS:5
Reset:21
Resetting WizNet for consistent results
Starting ethernet
w5100 init, using SS_PIN_DEFAULT = 13
W5100::init: W5500, SSIZE =4096
W5500 hardware found
LinkON
LocalIP:192.168.2.78
GW:192.168.2.1
Subnet Netmask:255.255.0.0
DNS Server IP:192.168.2.1
..
Connected to HueNet1
IP address: 192.168.2.69
filename=/index.htm
filesize=3714
filename=/index.htm
filesize=3714
filename=/index.htm
filesize=3714
filename=/index.htm
filesize=3714

Selection_377

Selection_378

@workpage2
Copy link
Author

workpage2 commented May 4, 2020

you have 2 ip addresses. Test 192.168.2.78
My index.html is 30kb in size, it loads 3 seconds via ethernet.
The same page via wifi loads instantly.

@khoih-prog
Copy link
Owner

You can see 78 and 69 both tested in the pictures

78=>
image

69

image

@workpage2
Copy link
Author

workpage2 commented May 4, 2020

Upload large index.html and check the download time.

@workpage2
Copy link
Author

Buffer overflow solution on w5100
ejeklint/ArduinoWebsocketServer#19

@khoih-prog
Copy link
Owner

@workpage2

Can you try using Ethernet3 lib to see if the problem relating to Ethernet lib only

Sketch change

#include <FS.h>  // Библиотека для работы с файловой системой
#include <SPIFFS.h>
#include "SPI.h"

#define USE_ETHERNET          true

#define USE_ETHERNET3         true
#define USE_ETHERNET_LARGE    false

#if ( USE_ETHERNET3 || USE_ETHERNET_LARGE )
#ifdef USE_ETHERNET
#undef USE_ETHERNET
#define USE_ETHERNET          false
#endif
#endif

#if USE_ETHERNET3
#include "Ethernet3.h"
#warning Use Ethernet3 lib
#elif USE_ETHERNET_LARGE
#include "EthernetLarge.h"
#warning Use EthernetLarge lib
#else
#include "Ethernet.h"
#warning Use Ethernet lib
#endif

#include "WebServer_Webduino.h" //This is WebDuino library!!!!!!!!!!!!!!!!!! 
//you can download this library from https://github.com/sirleech/Webduino, change WebServer.h to WebServer_Webduino.h

#define EthernetLinkUP_Retries  10  //
bool tcp_session = false;

#define W5500_RST_PORT   21
byte mac[] = {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
bool EthernetUsable = false;  // W5500 found??

#include <WiFi.h>
//const char* ssid = "SSID";
//const char* password = "PASS";
const char* ssid = "HueNet1";
const char* password = "jenniqqs";

#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
AsyncWebServer server(80);
const char* PARAM_MESSAGE = "message";

EthernetClient e_client;
WiFiClient w_client;

void notFound(AsyncWebServerRequest *request) {
  request->send(404, "text/plain", "Not found");
}

/* CHANGE THIS TO YOUR OWN UNIQUE VALUE.  The MAC number should be
  different from any other devices on your network or you'll have
  problems receiving packets. */
//static uint8_t mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

/* CHANGE THIS TO MATCH YOUR HOST NETWORK.  Most home networks are in
  the 192.168.0.XXX or 192.168.1.XXX subrange.  Pick an address
  that's not in use and isn't going to be automatically allocated by
  DHCP from your router. */
//static uint8_t ip[] = { 192, 168, 2, 210 };

/* This creates an instance of the webserver.  By specifying a prefix
  of "", all pages will be at the root of the server. */
#define PREFIX ""
WebServer webserver(PREFIX, 80);

/* commands are functions that get called by the webserver framework
  they can read any posted data from client, and they output to the
  server to send data back to the web browser. */
void helloCmd(WebServer &server, WebServer::ConnectionType type, char *, bool)
{
  String temp;
  char temp2;
  String filename;
  unsigned int fileexit;
  /* this line sends the standard "we're all OK" headers back to the
    browser */
  server.httpSuccess();

  /* if we're handling a GET or POST, we can output our data here.
    For a HEAD request, we just stop after outputting headers. */
  if (type != WebServer::HEAD)
  {
    /* this defines some HTML text in read-only memory aka PROGMEM.
      This is needed to avoid having the string copied to our limited
      amount of RAM. */
    //P(helloMsg) = "<h1>Hello, World! from print</h1>";
    /* this is a special form of print that outputs from PROGMEM */
    //server.printP(helloMsg);

    //filename="/index.html";
    filename = "/index.htm";

    if (SPIFFS.exists(filename))
    {
      // If a file exists at the address of the file system
      File file = SPIFFS.open(filename, "r");
      // Open the file for reading
      Serial.print("filename=");
      Serial.println(filename);
      Serial.print("filesize=");
      Serial.println(file.size());

      while (file.available())
      {
        temp2 = file.read();
        //Serial.write(temp2);
        temp = temp + temp2;
        fileexit++;
        if (fileexit == 950)
        {
          server.print(temp);
          fileexit = 0;
          temp = "";
        }
      }
      file.close();
    }
    else temp = "File not found";
    server.print(temp);
  }
}

//format bytes
String formatBytes(size_t bytes)
{
  if (bytes < 1024)
  {
    return String(bytes) + "B";
  }
  else if (bytes < (1024 * 1024))
  {
    return String(bytes / 1024.0) + "KB";
  }
  else if (bytes < (1024 * 1024 * 1024))
  {
    return String(bytes / 1024.0 / 1024.0) + "MB";
  }
  else
  {
    return String(bytes / 1024.0 / 1024.0 / 1024.0) + "GB";
  }
}

void setup()
{
  Serial.begin(115200);
  while (!Serial);
  Serial.println("\nStarting ESP32_SPIFFS_Test");

  SPIFFS.begin();

  // List all files present in SPIFFS
  File root = SPIFFS.open("/");
  File file = root.openNextFile();
  while (file)
  {
    String fileName = file.name();
    size_t fileSize = file.size();
    Serial.printf("FS File: %s, size: %s\n", fileName.c_str(), formatBytes(fileSize).c_str());
    file = root.openNextFile();
  }
  Serial.printf("\n");

  Serial.println("Used/default ESP32 pinout:");
  Serial.print("MOSI:");
  Serial.println(MOSI);
  Serial.print("MISO:");
  Serial.println(MISO);
  Serial.print("SCK:");
  Serial.println(SCK);
  Serial.print("SS:");
  Serial.println(SS);
  Serial.print("Reset:");
  Serial.println(W5500_RST_PORT);

  SPI.begin();

  Serial.println("Resetting WizNet for consistent results");
  pinMode(W5500_RST_PORT, OUTPUT);
  digitalWrite(W5500_RST_PORT, LOW);
  delayMicroseconds(500);
  digitalWrite(W5500_RST_PORT, HIGH);
  delayMicroseconds(1000);

  // https://www.arduino.cc/en/Reference/EthernetInit
  // 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
  // Don't need with fixed Ethernet lib
  //Ethernet.init(SS);    // NOT optional!!!

  Serial.println("Starting ethernet");
  // https://www.arduino.cc/en/Reference/EthernetBegin
  // Ethernet.begin takes about 60 seconds when cable is not connected ...... This is not always acceptable..
  // https://stackoverflow.com/questions/8530102/ethernet-begin-blocks-for-60-seconds-if-theres-no-ethernet-cable
  // DHCP seems to hold a 60 second timeout....

#if ( USE_ETHERNET3 )
  // For Ethernet3, ESP8266 OK with D0(GPIO16), D1(GPIO5), D2(GPIO4), D3(GPIO0)
  // , D4(2), D8() not OK
  Ethernet.setCsPin (13);
#endif
  
  Ethernet.begin(mac);
  // Use static IP
  //Ethernet.begin(mac,ip);

// Just info to know how to connect correctly
  Serial.println("=========================");
  Serial.println("Used/default SPI pinout:");
  Serial.print("MOSI:");
  Serial.println(MOSI);
  Serial.print("MISO:");
  Serial.println(MISO);
  Serial.print("SCK:");
  Serial.println(SCK);
  Serial.print("SS:");
  Serial.println(SS);

#if USE_ETHERNET3  
  Serial.print("SPI_CS:");
  Serial.println(SPI_CS);
  Serial.println("=========================");
#endif    

  //delay(1000);
  vTaskDelay(1000 / portTICK_RATE_MS);

#if ( USE_ETHERNET )

  switch (Ethernet.hardwareStatus()) {
    case EthernetNoHardware:
      Serial.println("Ethernet Hardware was not found, can't continue...");
      EthernetUsable = false;
      break;
    case EthernetW5100:
      Serial.println("W5100 hardware found");
      EthernetUsable = true;
      break;
    case EthernetW5200:
      Serial.println("W5200 hardware found");
      EthernetUsable = true;
      break;
    case EthernetW5500:
      Serial.println("W5500 hardware found");
      EthernetUsable = true;
      break;
    default:
      Serial.print("Undefined hardware found:");
      Serial.println(Ethernet.hardwareStatus());

      Serial.print("No Hardware value::");
      Serial.println(EthernetNoHardware);
      EthernetUsable = false;  // not acceptable
      break;
  }

  int retries = 0;
  do 
  {
    //delay(500);
    vTaskDelay(500 / portTICK_RATE_MS);

    switch (Ethernet.linkStatus()) {
      case Unknown:
        Serial.println("Unknown link status");
        EthernetUsable = false;
        break;
      case LinkOFF:
        Serial.println("LinkOFF");
        EthernetUsable = false;
        break;
      case LinkON:
        Serial.println("LinkON");
        EthernetUsable = true;
        break;
      default:
        EthernetUsable = false;
        Serial.println("Undefined link status");
    }
  } while ( (Ethernet.linkStatus() != LinkON ) && retries++ < EthernetLinkUP_Retries );

  if (EthernetUsable == true) 
#endif
  {
    // https://www.pjrc.com/arduino-ethernet-library-2-0-0/
    Serial.print("LocalIP:");
    Serial.println(Ethernet.localIP());

    Serial.print("GW:");
    Serial.println(Ethernet.gatewayIP());

    Serial.print("Subnet Netmask:");
    Serial.println(Ethernet.subnetMask());

    Serial.print("DNS Server IP:");
    Serial.println(Ethernet.dnsServerIP());

    //Serial.print("MAC:");
    //Serial.println(Ethernet.MACAddress());
  }

  WiFi.mode(WIFI_STA);
  //Esp_wifi_set_ps (WIFI_PS_NONE);
  WiFi.setSleep(false);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) 
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
    request->send(200, "text/plain", "Hello, world from async");
  });

  server.onNotFound(notFound);

  server.begin();

  /* setup our default command that will be run when the user accesses
     the root page on the server */
  webserver.setDefaultCommand(&helloCmd);

  /* run the same command if you try to load /index.html, a common
     default page name */
  webserver.addCommand("index.html", &helloCmd);

  /* start the webserver */
  webserver.begin();
}

void loop()
{
  char buff[64];
  int len = 64;

  /* process incoming connections one at a time forever */
  webserver.processConnection(buff, &len);
}

You just need to change the Webduino's WebServer.h into WebServer_Webduino.h and don't need to erase Standard webserver.h library

WebServer_Webduino.h mod

#ifndef WEBDUINO_H_
#define WEBDUINO_H_

#include <string.h>
#include <stdlib.h>

//#include <Ethernet.h>

#if USE_ETHERNET3
#include "Ethernet3.h"
#warning Use Ethernet3 lib
#elif USE_ETHERNET_LARGE
#include "EthernetLarge.h"
#warning Use EthernetLarge lib
#else
#include "Ethernet.h"
#warning Use Ethernet lib
#endif

#include <EthernetClient.h>
#include <EthernetServer.h>

/********************************************************************
 * CONFIGURATION
 ********************************************************************/
...

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants