Долго бьюсь над проблемой. Не могу заставить нормально работать ethernet на esp32.
Подключен внешний ethernet чип на w5500 через spi.
Распиновка следующая:
MOSI:23
MISO:19
SCK:18
SS:5
RESET:21
Простейшие web серверы работают. С этим проблем нет.
Но если брать большую страницу, то нужно внешнее хранилище. SPIFFS, в данном случае.
А вот тут затык. Не работает одновременно spiffs и ethernet.
Точнее функция streamfile (Код ниже). Соединение устанавливается, а данные не идут. Ни одного байта. Всё тоже самое через wifi работает аж бегом.
Сделал костыль. Читаю сначала файл в строковую переменную, а затем отправляю в полёт. Но всё упирается в размер буфера w5500 - 2кб.
Если файл меньше 2кб - всё работает. Если больше - загружается только первые 2 кб. Фигня короче... Были мысли пауз навтыкать в библиотеку - но это сначала надо в ней разобраться, и потом костыль же... Надо нормальное решение.
Кто-нибудь делал web сервер на esp32 + ethernet (ЛЮБОЙ!!!). Напишите. Идеи кончились.
Подключен внешний ethernet чип на w5500 через spi.
Распиновка следующая:
MOSI:23
MISO:19
SCK:18
SS:5
RESET:21
Простейшие web серверы работают. С этим проблем нет.
Но если брать большую страницу, то нужно внешнее хранилище. SPIFFS, в данном случае.
А вот тут затык. Не работает одновременно spiffs и ethernet.
Точнее функция streamfile (Код ниже). Соединение устанавливается, а данные не идут. Ни одного байта. Всё тоже самое через wifi работает аж бегом.
Сделал костыль. Читаю сначала файл в строковую переменную, а затем отправляю в полёт. Но всё упирается в размер буфера w5500 - 2кб.
Если файл меньше 2кб - всё работает. Если больше - загружается только первые 2 кб. Фигня короче... Были мысли пауз навтыкать в библиотеку - но это сначала надо в ней разобраться, и потом костыль же... Надо нормальное решение.
Кто-нибудь делал web сервер на esp32 + ethernet (ЛЮБОЙ!!!). Напишите. Идеи кончились.
C++:
#include <FS.h> // Библиотека для работы с файловой системой
#include <SPIFFS.h>
#include <SPI.h>
#include <Ethernet.h>
bool tcp_session = false;
bool EthernetUsable = false; // W5500 found??
String temp;
char temp2;
//#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");
// 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());
}
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){ // Функция работы с файловой системой
String temp; //ЭТО КОСТЫЛЬ!!!!!!!!!!!!!!!!
char temp2; //И ЭТО ТОЖЕ!!!!!!!!!!!!!!!!!
//Serial.println(HTTP.uri());
if(path.endsWith("/")) path += "index.html"; // Если устройство вызывается по корневому адресу, то должен вызываться файл index.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 (если не обработалось предыдущее условие)
}
String getContentType(String filename){ // Функция, возвращающая необходимый заголовок типа содержимого в зависимости от расширения файла
if (filename.endsWith(".html")) return "text/html"; // Если файл заканчивается на ".html", то возвращаем заголовок "text/html" и завершаем выполнение функции
//if (filename.endsWith(".html")) return "text/plain"; // Если файл заканчивается на ".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"; // Если ни один из типов файла не совпал, то считаем что содержимое файла текстовое, отдаем соответствующий заголовок и завершаем выполнение функции
}