mirror of
https://git.mirrors.martin98.com/https://github.com/luc-github/ESP3D.git
synced 2025-06-06 02:36:49 +08:00
1275 lines
52 KiB
C++
1275 lines
52 KiB
C++
/*
|
|
asyncwebserver.cpp - ESP3D sync functions class
|
|
|
|
Copyright (c) 2014 Luc Lebosse. All rights reserved.
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include <pgmspace.h>
|
|
#include "config.h"
|
|
#if defined(ASYNCWEBSERVER)
|
|
|
|
#include "webinterface.h"
|
|
#include "wificonf.h"
|
|
#include <WiFiClient.h>
|
|
#include <WiFiServer.h>
|
|
#include <WiFiUdp.h>
|
|
#include <StreamString.h>
|
|
#ifndef FS_NO_GLOBALS
|
|
#define FS_NO_GLOBALS
|
|
#endif
|
|
#include <FS.h>
|
|
#include <ESPAsyncWebServer.h>
|
|
#ifdef ARDUINO_ARCH_ESP8266
|
|
#include "ESP8266WiFi.h"
|
|
#include <ESPAsyncTCP.h>
|
|
#else //ESP32
|
|
#include <WiFi.h>
|
|
#include <AsyncTCP.h>
|
|
#include "SPIFFS.h"
|
|
#include "Update.h"
|
|
#endif
|
|
|
|
#include "GenLinkedList.h"
|
|
#include "command.h"
|
|
#include "espcom.h"
|
|
|
|
#ifdef SSDP_FEATURE
|
|
#ifdef ARDUINO_ARCH_ESP32
|
|
#include <ESP32SSDP.h>
|
|
#else
|
|
#include <ESP8266SSDP.h>
|
|
#endif
|
|
#endif
|
|
|
|
//embedded response file if no files on SPIFFS
|
|
#include "nofile.h"
|
|
bool can_process_serial = true;
|
|
|
|
extern bool deleteRecursive(String path);
|
|
extern bool sendLine2Serial (String & line, int32_t linenb, int32_t * newlinenb);
|
|
extern void CloseSerialUpload (bool iserror, String & filename, int32_t linenb);
|
|
extern bool purge_serial();
|
|
extern long id_connection;
|
|
|
|
const uint8_t PAGE_404 [] PROGMEM = "<HTML>\n<HEAD>\n<title>Redirecting...</title> \n</HEAD>\n<BODY>\n<CENTER>Unknown page : $QUERY$- you will be redirected...\n<BR><BR>\nif not redirected, <a href='http://$WEB_ADDRESS$'>click here</a>\n<BR><BR>\n<PROGRESS name='prg' id='prg'></PROGRESS>\n\n<script>\nvar i = 0; \nvar x = document.getElementById(\"prg\"); \nx.max=5; \nvar interval=setInterval(function(){\ni=i+1; \nvar x = document.getElementById(\"prg\"); \nx.value=i; \nif (i>5) \n{\nclearInterval(interval);\nwindow.location.href='/';\n}\n},1000);\n</script>\n</CENTER>\n</BODY>\n</HTML>\n\n";
|
|
const uint8_t PAGE_CAPTIVE [] PROGMEM = "<HTML>\n<HEAD>\n<title>Captive Portal</title> \n</HEAD>\n<BODY>\n<CENTER>Captive Portal page : $QUERY$- you will be redirected...\n<BR><BR>\nif not redirected, <a href='http://$WEB_ADDRESS$'>click here</a>\n<BR><BR>\n<PROGRESS name='prg' id='prg'></PROGRESS>\n\n<script>\nvar i = 0; \nvar x = document.getElementById(\"prg\"); \nx.max=5; \nvar interval=setInterval(function(){\ni=i+1; \nvar x = document.getElementById(\"prg\"); \nx.value=i; \nif (i>5) \n{\nclearInterval(interval);\nwindow.location.href='/';\n}\n},1000);\n</script>\n</CENTER>\n</BODY>\n</HTML>\n\n";
|
|
#define CONTENT_TYPE_HTML "text/html"
|
|
|
|
//filter to intercept command line on root
|
|
bool filterOnRoot (AsyncWebServerRequest *request)
|
|
{
|
|
if (request->hasArg ("forcefallback") ) {
|
|
String stmp = request->arg ("forcefallback");
|
|
//to use all case
|
|
stmp.toLowerCase();
|
|
if ( stmp == "yes") {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void handle_login(AsyncWebServerRequest *request)
|
|
{
|
|
#ifdef AUTHENTICATION_FEATURE
|
|
#else
|
|
AsyncWebServerResponse * response = request->beginResponse (200, "application/json", "{\"status\":\"Ok\",\"authentication_lvl\":\"admin\"}");
|
|
response->addHeader("Cache-Control","no-cache");
|
|
request->send(response);
|
|
#endif
|
|
}
|
|
|
|
|
|
#ifdef SSDP_FEATURE
|
|
void handle_SSDP (AsyncWebServerRequest *request)
|
|
{
|
|
StreamString sschema ;
|
|
if (sschema.reserve (1024) ) {
|
|
String templ = "<?xml version=\"1.0\"?>"
|
|
"<root xmlns=\"urn:schemas-upnp-org:device-1-0\">"
|
|
"<specVersion>"
|
|
"<major>1</major>"
|
|
"<minor>0</minor>"
|
|
"</specVersion>"
|
|
"<URLBase>http://%s:%u/</URLBase>"
|
|
"<device>"
|
|
"<deviceType>upnp:rootdevice</deviceType>"
|
|
"<friendlyName>%s</friendlyName>"
|
|
"<presentationURL>/</presentationURL>"
|
|
"<serialNumber>%s</serialNumber>"
|
|
#ifdef ARDUINO_ARCH_ESP32
|
|
"<modelName>ESP32</modelName>"
|
|
#else
|
|
"<modelName>ESP8266</modelName>"
|
|
#endif
|
|
"<modelNumber>ESP3D</modelNumber>"
|
|
#ifdef ARDUINO_ARCH_ESP32
|
|
"<modelURL>http://espressif.com/en/products/hardware/esp-wroom-32/overview</modelURL>"
|
|
#else
|
|
"<modelURL>http://espressif.com/en/products/esp8266</modelURL>"
|
|
#endif
|
|
"<manufacturer>Espressif Systems</manufacturer>"
|
|
"<manufacturerURL>http://espressif.com</manufacturerURL>"
|
|
"<UDN>uuid:%s</UDN>"
|
|
"</device>"
|
|
"</root>\r\n"
|
|
"\r\n";
|
|
char uuid[37];
|
|
String sip = WiFi.localIP().toString();
|
|
#ifdef ARDUINO_ARCH_ESP8266
|
|
uint32_t chipId = ESP.getChipId();
|
|
#else
|
|
uint32_t chipId = (uint16_t) (ESP.getEfuseMac() >> 32);
|
|
#endif
|
|
sprintf (uuid, "38323636-4558-4dda-9188-cda0e6%02x%02x%02x",
|
|
(uint16_t) ( (chipId >> 16) & 0xff),
|
|
(uint16_t) ( (chipId >> 8) & 0xff),
|
|
(uint16_t) chipId & 0xff );
|
|
String friendlyName;
|
|
if (!CONFIG::read_string (EP_HOSTNAME, friendlyName, MAX_HOSTNAME_LENGTH) ) {
|
|
friendlyName = wifi_config.get_default_hostname();
|
|
}
|
|
String serialNumber = String (chipId);
|
|
sschema.printf (templ.c_str(),
|
|
sip.c_str(),
|
|
wifi_config.iweb_port,
|
|
friendlyName.c_str(),
|
|
serialNumber.c_str(),
|
|
uuid);
|
|
request->send (200, "text/xml", (String) sschema);
|
|
} else {
|
|
request->send (500);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//SPIFFS
|
|
//SPIFFS files list and file commands
|
|
void handleFileList (AsyncWebServerRequest *request)
|
|
{
|
|
level_authenticate_type auth_level = web_interface->is_authenticated();
|
|
if (auth_level == LEVEL_GUEST) {
|
|
web_interface->_upload_status = UPLOAD_STATUS_NONE;
|
|
request->send (401, "text/plain", "Authentication failed!\n");
|
|
return;
|
|
}
|
|
String path ;
|
|
String status = "Ok";
|
|
if ( (web_interface->_upload_status == UPLOAD_STATUS_FAILED) || (web_interface->_upload_status == UPLOAD_STATUS_CANCELLED) ) {
|
|
status = "Upload failed";
|
|
}
|
|
//be sure root is correct according authentication
|
|
if (auth_level == LEVEL_ADMIN) {
|
|
path = "/";
|
|
} else {
|
|
path = "/user";
|
|
}
|
|
//get current path
|
|
if (request->hasArg ("path") ) {
|
|
path += request->arg ("path") ;
|
|
}
|
|
//to have a clean path
|
|
path.trim();
|
|
path.replace ("//", "/");
|
|
if (path[path.length() - 1] != '/') {
|
|
path += "/";
|
|
}
|
|
//check if query need some action
|
|
if (request->hasArg ("action") ) {
|
|
//delete a file
|
|
if (request->arg ("action") == "delete" && request->hasArg ("filename") ) {
|
|
String filename;
|
|
String shortname = request->arg ("filename");
|
|
shortname.replace ("/", "");
|
|
filename = path + request->arg ("filename");
|
|
filename.replace ("//", "/");
|
|
if (!SPIFFS.exists (filename) ) {
|
|
status = shortname + F (" does not exists!");
|
|
} else {
|
|
if (SPIFFS.remove (filename) ) {
|
|
status = shortname + F (" deleted");
|
|
//what happen if no "/." and no other subfiles ?
|
|
#ifdef ARDUINO_ARCH_ESP8266
|
|
FS_DIR dir = SPIFFS.openDir (path);
|
|
if (!dir.next() ) {
|
|
#else
|
|
String ptmp = path;
|
|
if ( (path != "/") && (path[path.length() - 1] = '/') ) {
|
|
ptmp = path.substring (0, path.length() - 1);
|
|
}
|
|
FS_FILE dir = SPIFFS.open (ptmp);
|
|
FS_FILE dircontent = dir.openNextFile();
|
|
if (!dircontent) {
|
|
#endif
|
|
//keep directory alive even empty
|
|
FS_FILE r = SPIFFS.open (path + "/.", SPIFFS_FILE_WRITE);
|
|
if (r) {
|
|
r.close();
|
|
}
|
|
}
|
|
} else {
|
|
status = F ("Cannot deleted ") ;
|
|
status += shortname ;
|
|
}
|
|
}
|
|
}
|
|
//delete a directory
|
|
if (request->arg ("action") == "deletedir" && request->hasArg ("filename") ) {
|
|
String filename;
|
|
String shortname = request->arg ("filename");
|
|
shortname.replace ("/", "");
|
|
filename = path + request->arg ("filename");
|
|
filename += "/";
|
|
filename.replace ("//", "/");
|
|
if (filename != "/") {
|
|
bool delete_error = false;
|
|
#ifdef ARDUINO_ARCH_ESP8266
|
|
FS_DIR dir = SPIFFS.openDir (path + shortname);
|
|
{
|
|
while (dir.next() ) {
|
|
#else
|
|
FS_FILE dir = SPIFFS.open (path + shortname);
|
|
{
|
|
FS_FILE file2deleted = dir.openNextFile();
|
|
while (file2deleted) {
|
|
#endif
|
|
#ifdef ARDUINO_ARCH_ESP8266
|
|
String fullpath = dir.fileName();
|
|
#else
|
|
String fullpath = file2deleted.name();
|
|
#endif
|
|
if (!SPIFFS.remove (fullpath) ) {
|
|
delete_error = true;
|
|
status = F ("Cannot deleted ") ;
|
|
status += fullpath;
|
|
}
|
|
#ifdef ARDUINO_ARCH_ESP32
|
|
file2deleted = dir.openNextFile();
|
|
#endif
|
|
}
|
|
}
|
|
if (!delete_error) {
|
|
status = shortname ;
|
|
status += " deleted";
|
|
}
|
|
}
|
|
}
|
|
//create a directory
|
|
if (request->arg ("action") == "createdir" && request->hasArg ("filename") ) {
|
|
String filename;
|
|
filename = path + request->arg ("filename") + "/.";
|
|
String shortname = request->arg ("filename");
|
|
shortname.replace ("/", "");
|
|
filename.replace ("//", "/");
|
|
if (SPIFFS.exists (filename) ) {
|
|
status = shortname + F (" already exists!");
|
|
} else {
|
|
FS_FILE r = SPIFFS.open (filename, SPIFFS_FILE_WRITE);
|
|
if (!r) {
|
|
status = F ("Cannot create ");
|
|
status += shortname ;
|
|
} else {
|
|
r.close();
|
|
status = shortname + F (" created");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
String jsonfile = "{";
|
|
#ifdef ARDUINO_ARCH_ESP8266
|
|
FS_DIR dir = SPIFFS.openDir (path);
|
|
#else
|
|
String ptmp = path;
|
|
if ( (path != "/") && (path[path.length() - 1] = '/') ) {
|
|
ptmp = path.substring (0, path.length() - 1);
|
|
}
|
|
FS_FILE dir = SPIFFS.open (ptmp);
|
|
#endif
|
|
jsonfile += "\"files\":[";
|
|
bool firstentry = true;
|
|
String subdirlist = "";
|
|
#ifdef ARDUINO_ARCH_ESP8266
|
|
while (dir.next() ) {
|
|
String filename = dir.fileName();
|
|
#else
|
|
File fileparsed = dir.openNextFile();
|
|
while (fileparsed) {
|
|
String filename = fileparsed.name();
|
|
#endif
|
|
String size = "";
|
|
bool addtolist = true;
|
|
//remove path from name
|
|
filename = filename.substring (path.length(), filename.length() );
|
|
//check if file or subfile
|
|
if (filename.indexOf ("/") > -1) {
|
|
//Do not rely on "/." to define directory as SPIFFS upload won't create it but directly files
|
|
//and no need to overload SPIFFS if not necessary to create "/." if no need
|
|
//it will reduce SPIFFS available space so limit it to creation
|
|
filename = filename.substring (0, filename.indexOf ("/") );
|
|
String tag = "*";
|
|
tag += filename + "*";
|
|
if (subdirlist.indexOf (tag) > -1 || filename.length() == 0) { //already in list
|
|
addtolist = false; //no need to add
|
|
} else {
|
|
size = "-1"; //it is subfile so display only directory, size will be -1 to describe it is directory
|
|
if (subdirlist.length() == 0) {
|
|
subdirlist += "*";
|
|
}
|
|
subdirlist += filename + "*"; //add to list
|
|
}
|
|
} else {
|
|
//do not add "." file
|
|
if (! ( (filename == ".") || (filename == "") ) ) {
|
|
#ifdef ARDUINO_ARCH_ESP8266
|
|
size = CONFIG::formatBytes (dir.fileSize() );
|
|
#else
|
|
size = CONFIG::formatBytes (fileparsed.size() );
|
|
#endif
|
|
|
|
} else {
|
|
addtolist = false;
|
|
}
|
|
}
|
|
if (addtolist) {
|
|
if (!firstentry) {
|
|
jsonfile += ",";
|
|
} else {
|
|
firstentry = false;
|
|
}
|
|
jsonfile += "{";
|
|
jsonfile += "\"name\":\"";
|
|
jsonfile += filename;
|
|
jsonfile += "\",\"size\":\"";
|
|
jsonfile += size;
|
|
jsonfile += "\"";
|
|
jsonfile += "}";
|
|
}
|
|
#ifdef ARDUINO_ARCH_ESP32
|
|
fileparsed = dir.openNextFile();
|
|
#endif
|
|
}
|
|
jsonfile += "],";
|
|
jsonfile += "\"path\":\"" + path + "\",";
|
|
jsonfile += "\"status\":\"" + status + "\",";
|
|
size_t totalBytes;
|
|
size_t usedBytes;
|
|
#ifdef ARDUINO_ARCH_ESP8266
|
|
fs::FSInfo info;
|
|
SPIFFS.info (info);
|
|
totalBytes = info.totalBytes;
|
|
usedBytes = info.usedBytes;
|
|
#else
|
|
totalBytes = SPIFFS.totalBytes();
|
|
usedBytes = SPIFFS.usedBytes();
|
|
#endif
|
|
jsonfile += "\"total\":\"" + CONFIG::formatBytes (totalBytes) + "\",";
|
|
jsonfile += "\"used\":\"" + CONFIG::formatBytes (usedBytes) + "\",";
|
|
jsonfile.concat (F ("\"occupation\":\"") );
|
|
jsonfile += CONFIG::intTostr (100 * usedBytes / totalBytes);
|
|
jsonfile += "\"";
|
|
jsonfile += "}";
|
|
path = "";
|
|
AsyncResponseStream *response = request->beginResponseStream ("application/json");
|
|
response->addHeader ("Cache-Control", "no-cache");
|
|
response->print (jsonfile.c_str() );
|
|
request->send (response);
|
|
web_interface->_upload_status = UPLOAD_STATUS_NONE;
|
|
}
|
|
|
|
//SPIFFS files uploader handle
|
|
void SPIFFSFileupload (AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final)
|
|
{
|
|
LOG ("Uploading: ")
|
|
LOG (filename)
|
|
LOG ("\n")
|
|
//get authentication status
|
|
level_authenticate_type auth_level= web_interface->is_authenticated();
|
|
//Guest cannot upload - only admin
|
|
if (auth_level == LEVEL_GUEST) {
|
|
web_interface->_upload_status = UPLOAD_STATUS_CANCELLED;
|
|
ESPCOM::println (F ("Upload rejected"), PRINTER_PIPE);
|
|
LOG ("Upload rejected\r\n");
|
|
request->client()->abort();
|
|
return;
|
|
}
|
|
String upload_filename = filename;
|
|
if (upload_filename[0] != '/') {
|
|
upload_filename = "/" + filename;
|
|
LOG ("Fix :")
|
|
LOG (upload_filename)
|
|
LOG ("\n")
|
|
}
|
|
if(auth_level != LEVEL_ADMIN) {
|
|
String filename = upload_filename;
|
|
upload_filename = "/user" + filename;
|
|
}
|
|
//Upload start
|
|
//**************
|
|
if (!index) {
|
|
LOG ("Upload start: ")
|
|
LOG ("filename")
|
|
LOG ("\n")
|
|
LOG (upload_filename)
|
|
if (SPIFFS.exists (upload_filename) ) {
|
|
SPIFFS.remove (upload_filename);
|
|
}
|
|
if (request->_tempFile) {
|
|
request->_tempFile.close();
|
|
}
|
|
request->_tempFile = SPIFFS.open (upload_filename, SPIFFS_FILE_WRITE);
|
|
if (!request->_tempFile) {
|
|
LOG ("Error")
|
|
request->client()->abort();
|
|
web_interface->_upload_status = UPLOAD_STATUS_FAILED;
|
|
} else {
|
|
web_interface->_upload_status = UPLOAD_STATUS_ONGOING;
|
|
}
|
|
|
|
}
|
|
//Upload write
|
|
//**************
|
|
if ( request->_tempFile) {
|
|
if ( ( web_interface->_upload_status = UPLOAD_STATUS_ONGOING) && len) {
|
|
request->_tempFile.write (data, len);
|
|
LOG ("Write file\n")
|
|
}
|
|
}
|
|
//Upload end
|
|
//**************
|
|
if (final) {
|
|
request->_tempFile.flush();
|
|
request->_tempFile.close();
|
|
request->_tempFile = SPIFFS.open (upload_filename, SPIFFS_FILE_READ);
|
|
uint32_t filesize = request->_tempFile.size();
|
|
request->_tempFile.close();
|
|
String sizeargname = filename + "S";
|
|
if (request->hasArg (sizeargname.c_str()) ) {
|
|
if (request->arg (sizeargname.c_str()) != String(filesize)) {
|
|
web_interface->_upload_status = UPLOAD_STATUS_FAILED;
|
|
SPIFFS.remove (upload_filename);
|
|
}
|
|
}
|
|
LOG ("Close file\n")
|
|
if (web_interface->_upload_status == UPLOAD_STATUS_ONGOING) {
|
|
web_interface->_upload_status = UPLOAD_STATUS_SUCCESSFUL;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//FW update using Web interface
|
|
#ifdef WEB_UPDATE_FEATURE
|
|
void handleUpdate (AsyncWebServerRequest *request)
|
|
{
|
|
level_authenticate_type auth_level = web_interface->is_authenticated();
|
|
if (auth_level != LEVEL_ADMIN) {
|
|
web_interface->_upload_status = UPLOAD_STATUS_NONE;
|
|
request->send (403, "text/plain", "Not allowed, log in first!\n");
|
|
return;
|
|
}
|
|
String jsonfile = "{\"status\":\"" ;
|
|
jsonfile += CONFIG::intTostr (web_interface->_upload_status);
|
|
jsonfile += "\"}";
|
|
//send status
|
|
AsyncResponseStream *response = request->beginResponseStream ("application/json");
|
|
response->addHeader ("Cache-Control", "no-cache");
|
|
response->print (jsonfile.c_str() );
|
|
request->send (response);
|
|
//if success restart
|
|
if (web_interface->_upload_status == UPLOAD_STATUS_SUCCESSFUL) {
|
|
web_interface->restartmodule = true;
|
|
} else {
|
|
web_interface->_upload_status = UPLOAD_STATUS_NONE;
|
|
}
|
|
}
|
|
void WebUpdateUpload (AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final)
|
|
{
|
|
static size_t last_upload_update;
|
|
static size_t totalSize;
|
|
static uint32_t maxSketchSpace ;
|
|
//only admin can update FW
|
|
if (web_interface->is_authenticated() != LEVEL_ADMIN) {
|
|
web_interface->_upload_status = UPLOAD_STATUS_CANCELLED;
|
|
request->client()->abort();
|
|
ESPCOM::println (F ("Update rejected"), PRINTER_PIPE);
|
|
LOG ("Update failed\r\n");
|
|
return;
|
|
}
|
|
//Upload start
|
|
//**************
|
|
if (!index) {
|
|
ESPCOM::println (F ("Update Firmware"), PRINTER_PIPE);
|
|
web_interface->_upload_status = UPLOAD_STATUS_ONGOING;
|
|
#ifdef ARDUINO_ARCH_ESP8266
|
|
Update.runAsync (true);
|
|
WiFiUDP::stopAll();
|
|
#endif
|
|
#ifdef ARDUINO_ARCH_ESP8266
|
|
maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
|
|
#else
|
|
//Not sure can do OTA on 2Mb board
|
|
maxSketchSpace = (ESP.getFlashChipSize() > 0x20000) ? 0x140000 : 0x140000 / 2;
|
|
#endif
|
|
last_upload_update = 0;
|
|
totalSize = 0;
|
|
if (!Update.begin (maxSketchSpace) ) { //start with max available size
|
|
web_interface->_upload_status = UPLOAD_STATUS_CANCELLED;
|
|
ESPCOM::println (F ("Update Cancelled"), PRINTER_PIPE);
|
|
request->client()->abort();
|
|
return;
|
|
} else {
|
|
if ( ( CONFIG::GetFirmwareTarget() == REPETIER4DV) || (CONFIG::GetFirmwareTarget() == REPETIER) ) {
|
|
ESPCOM::println (F ("Update 0%%"), PRINTER_PIPE);
|
|
} else {
|
|
ESPCOM::println (F ("Update 0%"), PRINTER_PIPE);
|
|
}
|
|
}
|
|
}
|
|
//Upload write
|
|
//**************
|
|
if (web_interface->_upload_status == UPLOAD_STATUS_ONGOING) {
|
|
//we do not know the total file size yet but we know the available space so let's use it
|
|
totalSize += len;
|
|
if ( ( (100 * totalSize) / maxSketchSpace) != last_upload_update) {
|
|
last_upload_update = (100 * totalSize) / maxSketchSpace;
|
|
String s = "Update ";
|
|
s+= String(last_upload_update);
|
|
|
|
if ( ( CONFIG::GetFirmwareTarget() == REPETIER4DV) || (CONFIG::GetFirmwareTarget() == REPETIER) ) {
|
|
s+="%%";
|
|
} else {
|
|
s+="%";
|
|
}
|
|
ESPCOM::println (s, PRINTER_PIPE);
|
|
}
|
|
if (Update.write (data, len) != len) {
|
|
web_interface->_upload_status = UPLOAD_STATUS_CANCELLED;
|
|
ESPCOM::println(F("Update Error"), PRINTER_PIPE);
|
|
Update.end();
|
|
request->client()->abort();
|
|
}
|
|
}
|
|
//Upload end
|
|
//**************
|
|
if (final) {
|
|
String sizeargname = filename + "S";
|
|
if (request->hasArg (sizeargname.c_str()) ) {
|
|
ESPCOM::println (F ("Check integrity"), PRINTER_PIPE);
|
|
if (request->arg (sizeargname.c_str()) != String(totalSize)) {
|
|
web_interface->_upload_status = UPLOAD_STATUS_FAILED;
|
|
ESPCOM::println (F ("Update Error"), PRINTER_PIPE);
|
|
Update.end();
|
|
request->client()->abort();
|
|
}
|
|
}
|
|
if (Update.end (true) ) { //true to set the size to the current progress
|
|
//Update is done
|
|
if ( ( CONFIG::GetFirmwareTarget() == REPETIER4DV) || (CONFIG::GetFirmwareTarget() == REPETIER) ) {
|
|
ESPCOM::println (F ("Update 100%%"), PRINTER_PIPE);
|
|
} else {
|
|
ESPCOM::println (F ("Update 100%"), PRINTER_PIPE);
|
|
}
|
|
web_interface->_upload_status = UPLOAD_STATUS_SUCCESSFUL;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//Not found Page handler //////////////////////////////////////////////////////////
|
|
void handle_not_found (AsyncWebServerRequest *request)
|
|
{
|
|
//if we are here it means no index.html
|
|
if (request->url() == "/") {
|
|
AsyncWebServerResponse * response = request->beginResponse_P (200, CONTENT_TYPE_HTML, PAGE_NOFILES, PAGE_NOFILES_SIZE);
|
|
response->addHeader ("Content-Encoding", "gzip");
|
|
request->send (response);
|
|
} else {
|
|
String path = F ("/404.htm");
|
|
String pathWithGz = path + F (".gz");
|
|
if (SPIFFS.exists (pathWithGz) || SPIFFS.exists (path) ) {
|
|
request->send (SPIFFS, path);
|
|
} else {
|
|
//if not template use default page
|
|
String contentpage = FPSTR (PAGE_404);
|
|
String stmp;
|
|
if (WiFi.getMode() == WIFI_STA ) {
|
|
stmp = WiFi.localIP().toString();
|
|
} else {
|
|
stmp = WiFi.softAPIP().toString();
|
|
}
|
|
//Web address = ip + port
|
|
String KEY_IP = F ("$WEB_ADDRESS$");
|
|
String KEY_QUERY = F ("$QUERY$");
|
|
if (wifi_config.iweb_port != 80) {
|
|
stmp += ":";
|
|
stmp += CONFIG::intTostr (wifi_config.iweb_port);
|
|
}
|
|
contentpage.replace (KEY_IP, stmp);
|
|
contentpage.replace (KEY_QUERY, request->url() );
|
|
request->send (404, CONTENT_TYPE_HTML, contentpage.c_str() );
|
|
}
|
|
}
|
|
}
|
|
|
|
//Handle web command query and send answer//////////////////////////////
|
|
void handle_web_command (AsyncWebServerRequest *request)
|
|
{
|
|
//to save time if already disconnected
|
|
if (request->hasArg ("PAGEID") ) {
|
|
if (request->arg ("PAGEID").length() > 0 ) {
|
|
if (request->arg ("PAGEID").toInt() != id_connection) {
|
|
request->send (200, "text/plain", "Invalid command");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
level_authenticate_type auth_level = web_interface->is_authenticated();
|
|
LOG (" Web command\r\n")
|
|
#ifdef DEBUG_ESP3D
|
|
int nb = request->args();
|
|
for (int i = 0 ; i < nb; i++) {
|
|
LOG (request->argName (i) )
|
|
LOG (":")
|
|
LOG (request->arg (i) )
|
|
LOG ("\r\n")
|
|
}
|
|
#endif
|
|
String cmd = "";
|
|
if (request->hasArg ("plain") || request->hasArg ("commandText") ) {
|
|
if (request->hasArg ("plain") ) {
|
|
cmd = request->arg ("plain");
|
|
} else {
|
|
cmd = request->arg ("commandText");
|
|
}
|
|
LOG ("Web Command:")
|
|
LOG (cmd)
|
|
LOG ("\r\n")
|
|
} else {
|
|
LOG ("invalid argument\r\n")
|
|
request->send (200, "text/plain", "Invalid command");
|
|
return;
|
|
}
|
|
//if it is for ESP module [ESPXXX]<parameter>
|
|
cmd.trim();
|
|
int ESPpos = cmd.indexOf ("[ESP");
|
|
if (ESPpos > -1) {
|
|
//is there the second part?
|
|
int ESPpos2 = cmd.indexOf ("]", ESPpos);
|
|
if (ESPpos2 > -1) {
|
|
//Split in command and parameters
|
|
String cmd_part1 = cmd.substring (ESPpos + 4, ESPpos2);
|
|
String cmd_part2 = "";
|
|
//only [ESP800] is allowed login free if authentication is enabled
|
|
if ( (auth_level == LEVEL_GUEST) && (cmd_part1.toInt() != 800) ) {
|
|
request->send (401, "text/plain", "Authentication failed!\n");
|
|
return;
|
|
}
|
|
//is there space for parameters?
|
|
if (ESPpos2 < cmd.length() ) {
|
|
cmd_part2 = cmd.substring (ESPpos2 + 1);
|
|
}
|
|
//if command is a valid number then execute command
|
|
if (cmd_part1.toInt() != 0) {
|
|
AsyncResponseStream *response = request->beginResponseStream ("text/html");
|
|
response->addHeader ("Cache-Control", "no-cache");
|
|
COMMAND::execute_command (cmd_part1.toInt(), cmd_part2, WEB_PIPE, auth_level, response);
|
|
request->send (response);
|
|
}
|
|
//if not is not a valid [ESPXXX] command
|
|
}
|
|
} else {
|
|
if (auth_level == LEVEL_GUEST) {
|
|
request->send (401, "text/plain", "Authentication failed!\n");
|
|
return;
|
|
}
|
|
//send command to serial as no need to transfer ESP command
|
|
//to avoid any pollution if Uploading file to SDCard
|
|
if ( (web_interface->blockserial) == false) {
|
|
//block every query
|
|
web_interface->blockserial = true;
|
|
LOG ("Block Serial\r\n")
|
|
//empty the serial buffer and incoming data
|
|
LOG ("Start PurgeSerial\r\n")
|
|
ESPCOM::processFromSerial (true);
|
|
LOG ("End PurgeSerial\r\n")
|
|
LOG ("Start PurgeSerial\r\n")
|
|
ESPCOM::processFromSerial (true);
|
|
LOG ("End PurgeSerial\r\n")
|
|
can_process_serial = false;
|
|
request->onDisconnect([request]() {
|
|
can_process_serial = true;
|
|
});
|
|
//send command
|
|
LOG ("Send Command\r\n")
|
|
ESPCOM::println (cmd, DEFAULT_PRINTER_PIPE);
|
|
CONFIG::wait (1);
|
|
AsyncWebServerResponse *response = request->beginChunkedResponse ("text/plain", [] (uint8_t *buffer, size_t maxLen, size_t index) -> size_t {
|
|
static bool finish_check;
|
|
static String current_line;
|
|
static int multiple_counter = 0;
|
|
static uint8_t *active_serial_buffer = NULL;
|
|
static size_t active_serial_buffer_size = 0;
|
|
uint32_t timeout = millis();
|
|
size_t count = 0;
|
|
LOG ("Entering\n")
|
|
//this is the start
|
|
if (!index)
|
|
{
|
|
//we are not done
|
|
finish_check = false;
|
|
//no error / multiple heat
|
|
multiple_counter = 0;
|
|
//if somehow the buffer is not empty - clean it
|
|
if (active_serial_buffer != NULL) {
|
|
delete active_serial_buffer;
|
|
active_serial_buffer = NULL;
|
|
}
|
|
active_serial_buffer_size = 0;
|
|
current_line = "";
|
|
}
|
|
//current_line is not empty because previous buffer was full
|
|
if (current_line.length() > 0 )
|
|
{
|
|
//does it have a end already ?
|
|
if (current_line[current_line.length() - 1] == '\n') {
|
|
LOG (current_line.c_str() )
|
|
//if yes fill the buffer
|
|
String tmp = "";
|
|
for (int p = 0 ; p < current_line.length() ; p++) {
|
|
CONFIG::wdtFeed();
|
|
//Just in case line is too long
|
|
if (count < maxLen) {
|
|
buffer[count] = current_line[p];
|
|
count++;
|
|
} //too long let's copy to buffer what's left for next time
|
|
else {
|
|
tmp += current_line[p];
|
|
}
|
|
}
|
|
//this will be sent next time
|
|
current_line = tmp;
|
|
}
|
|
}
|
|
LOG (" Max Len Size ")
|
|
LOG (String (maxLen) )
|
|
LOG (" Index ")
|
|
LOG (String (index) )
|
|
LOG (" initial count ")
|
|
LOG (String (count) )
|
|
LOG (" buffer ")
|
|
LOG (String (active_serial_buffer_size) )
|
|
LOG (" line ")
|
|
LOG (String (current_line.length() ) )
|
|
LOG ("\n")
|
|
int packet_size = (maxLen >= 1460) ? 1200 : maxLen;
|
|
//now check if serial has data if have space in send buffer
|
|
while (!finish_check && (count < maxLen) )
|
|
{
|
|
CONFIG::wdtFeed();
|
|
size_t len = ESPCOM::available(DEFAULT_PRINTER_PIPE);
|
|
LOG ("Input Size ")
|
|
LOG (String (len) )
|
|
LOG ("\n")
|
|
if (len > 0) {
|
|
//prepare serial buffer
|
|
uint8_t * tmp_buf = new uint8_t[active_serial_buffer_size + len];
|
|
//copy current buffer in new buffer
|
|
if ( (active_serial_buffer_size > 0) && (active_serial_buffer != NULL) ) {
|
|
for (int p = 0; p < active_serial_buffer_size; p++) {
|
|
tmp_buf[p] = active_serial_buffer[p];
|
|
}
|
|
delete active_serial_buffer;
|
|
}
|
|
//new sized buffer
|
|
active_serial_buffer = tmp_buf;
|
|
//read full buffer instead of read char by char
|
|
//so it give time to refill when processing
|
|
ESPCOM::readBytes (DEFAULT_PRINTER_PIPE, &active_serial_buffer[active_serial_buffer_size], len);
|
|
//new size of current buffer
|
|
active_serial_buffer_size += len;
|
|
}
|
|
LOG ("buffer Size ")
|
|
LOG (String (active_serial_buffer_size) )
|
|
LOG ("\n")
|
|
//if buffer is not empty let's process it
|
|
if (active_serial_buffer_size > 0) {
|
|
for (int p = 0; p < active_serial_buffer_size ; p++) {
|
|
//reset timeout
|
|
timeout = millis();
|
|
//feed WDT
|
|
CONFIG::wdtFeed();
|
|
//be sure there is some space
|
|
if (count < maxLen) {
|
|
//read next char
|
|
uint8_t c = active_serial_buffer[p];
|
|
//if it is end line
|
|
if ( (c == 13) || (c == 10) ) {
|
|
//it is an ok or a wait so this is the end
|
|
LOG ("line ")
|
|
LOG (current_line.c_str() )
|
|
if ( (current_line == "ok") || (current_line == "wait") || ( ( (CONFIG::GetFirmwareTarget() == REPETIER) || (CONFIG::GetFirmwareTarget() == REPETIER4DV) ) && ( (current_line.indexOf ("busy:") > -1) || (current_line.startsWith ( "ok ") ) ) ) ) {
|
|
LOG ("ignore ")
|
|
LOG (current_line.c_str() )
|
|
current_line = "";
|
|
//check we have something before we leave and it is not
|
|
//an ack for the command
|
|
if ( (index == 0) && (count == 0) ) {
|
|
multiple_counter ++ ;
|
|
} else {
|
|
finish_check = true;
|
|
}
|
|
//we do not ignore it
|
|
} else {
|
|
if (current_line.length() > 0) {
|
|
current_line += "\n";
|
|
//do we add current line to buffer or wait for next callback ?
|
|
if ( (count + current_line.length() ) < maxLen) {
|
|
LOG ("line added\n")
|
|
//have space so copy to buffer
|
|
for (int pp = 0 ; pp < current_line.length() ; pp++) {
|
|
buffer[count] = current_line[pp];
|
|
count++;
|
|
}
|
|
//CONFIG::wait(1);
|
|
timeout = millis();
|
|
if (COMMAND::check_command (current_line, NO_PIPE, false, false) ) {
|
|
multiple_counter ++ ;
|
|
}
|
|
//reset line
|
|
current_line = "";
|
|
//no space return and add next time
|
|
} else {
|
|
//we should never reach here - but better prevent
|
|
if (p < active_serial_buffer_size) {
|
|
uint8_t * tmp_buf = new uint8_t[active_serial_buffer_size - p];
|
|
//copy old one to new one
|
|
for (int pp = 0; pp < active_serial_buffer_size - p; pp++) {
|
|
tmp_buf[pp] = active_serial_buffer[p + pp];
|
|
}
|
|
//delete old one
|
|
if (active_serial_buffer != NULL) {
|
|
delete active_serial_buffer;
|
|
}
|
|
//now new is the active one
|
|
active_serial_buffer = tmp_buf;
|
|
//reset size
|
|
active_serial_buffer_size = active_serial_buffer_size - p;
|
|
}
|
|
return count;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
current_line += char (c);
|
|
//case of long line that won't fit
|
|
if (current_line.length() >= maxLen) {
|
|
//we push out what we have and what we can
|
|
//no need tp check if it is command as it is too long
|
|
for (int pp = 0 ; pp < current_line.length() ; pp++) {
|
|
CONFIG::wdtFeed();
|
|
if (count < maxLen) {
|
|
buffer[count] = current_line[pp];
|
|
count++;
|
|
} else { //put what is left for next time
|
|
//remove part already sent
|
|
String tmp = current_line.substring (pp);
|
|
current_line = tmp;
|
|
//save left buffer
|
|
if (p < active_serial_buffer_size) {
|
|
uint8_t * tmp_buf = new uint8_t[active_serial_buffer_size - p];
|
|
//copy old one to new one
|
|
for (int pp = 0; pp < active_serial_buffer_size - p; pp++) {
|
|
tmp_buf[pp] = active_serial_buffer[p + pp];
|
|
}
|
|
//delete old one
|
|
if (active_serial_buffer != NULL) {
|
|
delete active_serial_buffer;
|
|
}
|
|
//now new is the active one
|
|
active_serial_buffer = tmp_buf;
|
|
//reset size
|
|
active_serial_buffer_size = active_serial_buffer_size - p;
|
|
}
|
|
return count;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//no space return and add next time
|
|
} else {
|
|
//we should never reach here - but better prevent
|
|
//save unprocessed buffer
|
|
//create a resized buffer
|
|
uint8_t * tmp_buf = new uint8_t[active_serial_buffer_size - p];
|
|
//copy old one to new one
|
|
for (int pp = 0; pp < active_serial_buffer_size - p; pp++) {
|
|
tmp_buf[pp] = active_serial_buffer[p + pp];
|
|
}
|
|
//delete old one
|
|
if (active_serial_buffer != NULL) {
|
|
delete active_serial_buffer;
|
|
}
|
|
//now new is the active one
|
|
active_serial_buffer = tmp_buf;
|
|
//reset size
|
|
active_serial_buffer_size = active_serial_buffer_size - p;
|
|
return count;
|
|
}
|
|
}//end processing buffer Serial
|
|
active_serial_buffer_size = 0;
|
|
if (active_serial_buffer != NULL) {
|
|
delete active_serial_buffer;
|
|
}
|
|
active_serial_buffer = NULL;
|
|
//we chop to fill packect size not maxLen
|
|
if (count >= packet_size) {
|
|
//buffer is empty so time to clean
|
|
return count;
|
|
}
|
|
timeout = millis();
|
|
} //end of processing serial buffer
|
|
//we got several ok / wait /busy or temperature, so we should stop to avoid a dead loop
|
|
if (multiple_counter > 5) {
|
|
LOG ("Multiple counter reached\n\r")
|
|
finish_check = true;
|
|
}
|
|
//no input during 1 s so consider we are done and we missed the end flag
|
|
if (millis() - timeout > 1000) {
|
|
finish_check = true;
|
|
LOG ("time out\r\n")
|
|
}
|
|
} // we are done for this call : buffer is full or everything is finished
|
|
//if we are done
|
|
if (finish_check)
|
|
{
|
|
//do some cleaning if needed
|
|
active_serial_buffer_size = 0;
|
|
if (active_serial_buffer != NULL) {
|
|
delete active_serial_buffer;
|
|
}
|
|
active_serial_buffer = NULL;
|
|
}
|
|
return count;
|
|
});
|
|
response->addHeader ("Cache-Control", "no-cache");
|
|
request->send (response);
|
|
LOG ("Start PurgeSerial\r\n")
|
|
ESPCOM::processFromSerial (true);
|
|
LOG ("End PurgeSerial\r\n")
|
|
web_interface->blockserial = false;
|
|
LOG ("Release Serial\r\n")
|
|
} else {
|
|
request->send (409, "text/plain", "Serial is busy, retry later!");
|
|
}
|
|
}
|
|
}
|
|
|
|
//Handle web command query and sent ack or fail instead of answer///////
|
|
void handle_web_command_silent (AsyncWebServerRequest *request)
|
|
{
|
|
//to save time if already disconnected
|
|
if (request->hasArg ("PAGEID") ) {
|
|
if (request->arg ("PAGEID").length() > 0 ) {
|
|
if (request->arg ("PAGEID").toInt() != id_connection) {
|
|
request->send (200, "text/plain", "Invalid command");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
level_authenticate_type auth_level = web_interface->is_authenticated();
|
|
if (auth_level == LEVEL_GUEST) {
|
|
request->send (401, "text/plain", "Authentication failed!\n");
|
|
return;
|
|
}
|
|
LOG (String (request->args() ) )
|
|
LOG (" Web silent command\r\n")
|
|
#ifdef DEBUG_ESP3D
|
|
int nb = request->args();
|
|
for (int i = 0 ; i < nb; i++) {
|
|
LOG (request->argName (i) )
|
|
LOG (":")
|
|
LOG (request->arg (i) )
|
|
LOG ("\r\n")
|
|
}
|
|
#endif
|
|
String cmd = "";
|
|
//int count ;
|
|
if (request->hasArg ("plain") || request->hasArg ("commandText") ) {
|
|
if (request->hasArg ("plain") ) {
|
|
cmd = request->arg ("plain");
|
|
} else {
|
|
cmd = request->arg ("commandText");
|
|
}
|
|
LOG ("Web Command:")
|
|
LOG (cmd)
|
|
LOG ("\r\n")
|
|
} else {
|
|
LOG ("invalid argument\r\n")
|
|
request->send (200, "text/plain", "Invalid command");
|
|
return;
|
|
}
|
|
//if it is for ESP module [ESPXXX]<parameter>
|
|
cmd.trim();
|
|
int ESPpos = cmd.indexOf ("[ESP");
|
|
if (ESPpos > -1) {
|
|
//is there the second part?
|
|
int ESPpos2 = cmd.indexOf ("]", ESPpos);
|
|
if (ESPpos2 > -1) {
|
|
//Split in command and parameters
|
|
String cmd_part1 = cmd.substring (ESPpos + 4, ESPpos2);
|
|
String cmd_part2 = "";
|
|
//is there space for parameters?
|
|
if (ESPpos2 < cmd.length() ) {
|
|
cmd_part2 = cmd.substring (ESPpos2 + 1);
|
|
}
|
|
//if command is a valid number then execute command
|
|
if (cmd_part1.toInt() != 0) {
|
|
if (COMMAND::execute_command (cmd_part1.toInt(), cmd_part2, NO_PIPE, auth_level) ) {
|
|
request->send (200, "text/plain", "ok");
|
|
} else {
|
|
request->send (500, "text/plain", "error");
|
|
}
|
|
|
|
}
|
|
//if not is not a valid [ESPXXX] command
|
|
}
|
|
} else {
|
|
//send command to serial as no need to transfer ESP command
|
|
//to avoid any pollution if Uploading file to SDCard
|
|
if ( (web_interface->blockserial) == false) {
|
|
LOG ("Send Command\r\n")
|
|
//send command
|
|
ESPCOM::println (cmd, DEFAULT_PRINTER_PIPE);
|
|
|
|
request->send (200, "text/plain", "ok");
|
|
} else {
|
|
request->send (200, "text/plain", "Serial is busy, retry later!");
|
|
}
|
|
}
|
|
}
|
|
|
|
//serial SD files list//////////////////////////////////////////////////
|
|
void handle_serial_SDFileList (AsyncWebServerRequest *request)
|
|
{
|
|
//this is only for admin and user
|
|
if (web_interface->is_authenticated() == LEVEL_GUEST) {
|
|
web_interface->_upload_status = UPLOAD_STATUS_NONE;
|
|
request->send (401, "application/json", "{\"status\":\"Authentication failed!\"}");
|
|
return;
|
|
}
|
|
LOG ("serial SD upload done\r\n")
|
|
String sstatus = "Ok";
|
|
if ( (web_interface->_upload_status == UPLOAD_STATUS_FAILED) || (web_interface->_upload_status == UPLOAD_STATUS_CANCELLED) ) {
|
|
sstatus = "Upload failed";
|
|
web_interface->_upload_status = UPLOAD_STATUS_NONE;
|
|
}
|
|
String jsonfile = "{\"status\":\"" + sstatus + "\"}";
|
|
AsyncResponseStream *response = request->beginResponseStream ("application/json");
|
|
response->addHeader ("Cache-Control", "no-cache");
|
|
response->print (jsonfile.c_str() );
|
|
request->send (response);
|
|
web_interface->blockserial = false;
|
|
web_interface->_upload_status = UPLOAD_STATUS_NONE;
|
|
}
|
|
|
|
//SD file upload by serial
|
|
#define NB_RETRY 5
|
|
#define MAX_RESEND_BUFFER 128
|
|
#define SERIAL_CHECK_TIMEOUT 2000
|
|
void SDFile_serial_upload (AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final)
|
|
{
|
|
LOG ("Uploading: ")
|
|
LOG (filename)
|
|
LOG ("\n")
|
|
static int32_t lineNb =-1;
|
|
static String current_line;
|
|
static bool is_comment = false;
|
|
static String current_filename;
|
|
String response;
|
|
//Guest cannot upload - only admin and user
|
|
if (web_interface->is_authenticated() == LEVEL_GUEST) {
|
|
web_interface->_upload_status = UPLOAD_STATUS_CANCELLED;
|
|
ESPCOM::println (F ("SD upload rejected"), PRINTER_PIPE);
|
|
LOG ("SD upload rejected\r\n");
|
|
request->client()->abort();
|
|
return;
|
|
}
|
|
//Upload start
|
|
//**************
|
|
if (!index) {
|
|
LOG("Upload Start\r\n")
|
|
String command = "M29";
|
|
String resetcmd = "M110 N0";
|
|
if (CONFIG::GetFirmwareTarget() == SMOOTHIEWARE) {
|
|
resetcmd = "N0 M110";
|
|
}
|
|
lineNb=1;
|
|
//close any ongoing upload and get current line number
|
|
if(!sendLine2Serial (command,1, &lineNb)) {
|
|
//it can failed for repetier
|
|
if ( ( CONFIG::GetFirmwareTarget() == REPETIER4DV) || (CONFIG::GetFirmwareTarget() == REPETIER) ) {
|
|
if(!sendLine2Serial (command,-1, NULL)) {
|
|
LOG("Start Upload failed")
|
|
web_interface->_upload_status= UPLOAD_STATUS_FAILED;
|
|
return;
|
|
}
|
|
} else {
|
|
LOG("Start Upload failed")
|
|
web_interface->_upload_status= UPLOAD_STATUS_FAILED;
|
|
return;
|
|
}
|
|
}
|
|
//Mount SD card
|
|
command = "M21";
|
|
if(!sendLine2Serial (command,-1, NULL)) {
|
|
LOG("Mounting SD failed")
|
|
web_interface->_upload_status= UPLOAD_STATUS_FAILED;
|
|
return;
|
|
}
|
|
//Reset line numbering
|
|
if(!sendLine2Serial (resetcmd,-1, NULL)) {
|
|
LOG("Reset Numbering failed")
|
|
web_interface->_upload_status= UPLOAD_STATUS_FAILED;
|
|
return;
|
|
}
|
|
lineNb=1;
|
|
//need to lock serial out to avoid garbage in file
|
|
(web_interface->blockserial) = true;
|
|
current_line ="";
|
|
current_filename = filename;
|
|
is_comment = false;
|
|
String response;
|
|
ESPCOM::println (F ("Uploading..."), PRINTER_PIPE);
|
|
//Clear all serial
|
|
ESPCOM::flush (DEFAULT_PRINTER_PIPE);
|
|
purge_serial();
|
|
//besure nothing left again
|
|
purge_serial();
|
|
command = "M28 " + current_filename;
|
|
//send start upload
|
|
//no correction allowed because it means reset numbering was failed
|
|
if (sendLine2Serial(command, lineNb, NULL)) {
|
|
CONFIG::wait(1200);
|
|
//additional purge, in case it is slow to answer
|
|
purge_serial();
|
|
web_interface->_upload_status= UPLOAD_STATUS_ONGOING;
|
|
LOG("Creation Ok\r\n")
|
|
|
|
} else {
|
|
web_interface->_upload_status= UPLOAD_STATUS_FAILED;
|
|
LOG("Creation failed\r\n");
|
|
}
|
|
}
|
|
//Upload write
|
|
//**************
|
|
if ( ( web_interface->_upload_status = UPLOAD_STATUS_ONGOING) && len) {
|
|
LOG ("Writing to serial\n")
|
|
for (int pos = 0; pos < len; pos++) { //parse full post data
|
|
//feed watchdog
|
|
CONFIG::wdtFeed();
|
|
//it is a comment
|
|
if (data[pos] == ';') {
|
|
LOG ("Comment\n")
|
|
is_comment = true;
|
|
}
|
|
//it is an end line
|
|
else if ( (data[pos] == 13) || (data[pos] == 10) ) {
|
|
is_comment = false;
|
|
//does line fit the buffer ?
|
|
if (current_line.length() < 126) {
|
|
//do we have something in buffer ?
|
|
if (current_line.length() > 0 ) {
|
|
lineNb++;
|
|
if (!sendLine2Serial (current_line, lineNb, NULL) ) {
|
|
LOG ("Error sending line\n")
|
|
CloseSerialUpload (true, current_filename,lineNb);
|
|
request->client()->abort();
|
|
return;
|
|
}
|
|
//reset line
|
|
current_line = "";
|
|
//if comment line then reset
|
|
} else {
|
|
LOG ("Empy line\n")
|
|
}
|
|
} else {
|
|
//error buffer overload
|
|
LOG ("Error over buffer\n")
|
|
lineNb++;
|
|
CloseSerialUpload (true, current_filename, lineNb);
|
|
request->client()->abort();
|
|
return;
|
|
}
|
|
} else if (!is_comment) {
|
|
if (current_line.length() < 126) {
|
|
current_line += char (data[pos]); //copy current char to buffer to send/resend
|
|
} else {
|
|
LOG ("Error over buffer\n")
|
|
lineNb++;
|
|
CloseSerialUpload (true, current_filename, lineNb);
|
|
request->client()->abort();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
LOG ("Parsing Done\n")
|
|
} else {
|
|
LOG ("Nothing to write\n")
|
|
}
|
|
|
|
//Upload end
|
|
//**************
|
|
if (final) {
|
|
LOG ("Final is reached\n")
|
|
//if last part does not have '\n'
|
|
if (current_line.length() > 0) {
|
|
lineNb++;
|
|
if (!sendLine2Serial (current_line, lineNb, NULL) ) {
|
|
LOG ("Error sending buffer\n")
|
|
lineNb++;
|
|
CloseSerialUpload (true, current_filename, lineNb);
|
|
request->client()->abort();
|
|
return;
|
|
}
|
|
}
|
|
LOG ("Upload finished ");
|
|
lineNb++;
|
|
CloseSerialUpload (false, current_filename, lineNb);
|
|
}
|
|
LOG ("Exit fn\n")
|
|
}
|
|
|
|
|
|
//on event connect function
|
|
void handle_onevent_connect(AsyncEventSourceClient *client)
|
|
{
|
|
if (!client->lastId()) {
|
|
//Init active ID
|
|
id_connection++;
|
|
client->send(String(id_connection).c_str(), "InitID", id_connection, 1000);
|
|
//Dispatch who is active ID
|
|
web_interface->web_events.send( String(id_connection).c_str(),"ActiveID");
|
|
}
|
|
}
|
|
|
|
void handle_Websocket_Event(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len)
|
|
{
|
|
//Handle WebSocket event
|
|
}
|
|
|
|
#endif
|