diff --git a/esp3d/configuration.h b/esp3d/configuration.h index 0789f1a1..1513dce0 100644 --- a/esp3d/configuration.h +++ b/esp3d/configuration.h @@ -154,7 +154,7 @@ //Allow remote access by enabling cross origin access //check https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS -//this should be enabled only in specific cases +//this should be enabled only in specific cases //like show the camera in web page different than device web server //if you do not know what is that then better left it commented //#define ESP_ACCESS_CONTROL_ALLOW_ORIGIN diff --git a/esp3d/src/core/commands.cpp b/esp3d/src/core/commands.cpp index 14ccf90e..b4c7acc4 100644 --- a/esp3d/src/core/commands.cpp +++ b/esp3d/src/core/commands.cpp @@ -499,12 +499,19 @@ bool Commands::execute_internal_command (int cmd, const char* cmd_params, level_ response = ESP610(cmd_params, auth_type, output); break; #endif //NOTIFICATION_FEATURE -#ifdef FILESYSTEM_FEATURE +#if defined(FILESYSTEM_FEATURE) //Format ESP Filesystem //[ESP710]FORMAT pwd= case 710: response = ESP710(cmd_params, auth_type, output); break; +#endif //FILESYSTEM_FEATURE +#ifdef FILESYSTEM_FEATURE + //Open local file + //[ESP700] + case 700: + response = ESP700(cmd_params, auth_type, output); + break; //List ESP Filesystem //[ESP720] pwd= diff --git a/esp3d/src/core/commands.h b/esp3d/src/core/commands.h index 5eb61acc..5170cfb4 100644 --- a/esp3d/src/core/commands.h +++ b/esp3d/src/core/commands.h @@ -112,6 +112,9 @@ public: bool ESP600(const char* cmd_params, level_authenticate_type auth_level, ESP3DOutput * output); bool ESP610(const char* cmd_params, level_authenticate_type auth_level, ESP3DOutput * output); #endif //NOTIFICATION_FEATURE +#if defined(FILESYSTEM_FEATURE) + bool ESP700(const char* cmd_params, level_authenticate_type auth_level, ESP3DOutput * output); +#endif //FILESYSTEM_FEATURE #if defined(FILESYSTEM_FEATURE) bool ESP710(const char* cmd_params, level_authenticate_type auth_level, ESP3DOutput * output); bool ESP720(const char* cmd_params, level_authenticate_type auth_level, ESP3DOutput * output); diff --git a/esp3d/src/core/espcmd/ESP700.cpp b/esp3d/src/core/espcmd/ESP700.cpp new file mode 100644 index 00000000..5b19ffad --- /dev/null +++ b/esp3d/src/core/espcmd/ESP700.cpp @@ -0,0 +1,50 @@ +/* + ESP700.cpp - ESP3D command 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 "../../include/esp3d_config.h" +#if defined (FILESYSTEM_FEATURE) +#include "../commands.h" +#include "../esp3doutput.h" +#include "../settings_esp3d.h" +#include "../../modules/authentication/authentication_service.h" +#include "../../modules/filesystem/esp_filesystem.h" +#include "../../modules/gcode_host/gcode_host.h" +////read local file +//[ESP700] +bool Commands::ESP700(const char* cmd_params, level_authenticate_type auth_type, ESP3DOutput * output) +{ + bool response = true; + String parameter; + parameter = get_param (cmd_params, ""); +#ifdef AUTHENTICATION_FEATURE + if (auth_type != LEVEL_ADMIN) { + output->printERROR("Wrong authentication!", 401); + response = false; + } else +#else + (void)auth_type; +#endif //AUTHENTICATION_FEATURE + { + esp3d_gcode_host.processFile(parameter.c_str(), auth_type, output); + output->printMSG("ok"); + } + return response; +} + +#endif //FILESYSTEM_FEATURE diff --git a/esp3d/src/modules/camera/camera.cpp b/esp3d/src/modules/camera/camera.cpp index bc6bece9..443dc196 100644 --- a/esp3d/src/modules/camera/camera.cpp +++ b/esp3d/src/modules/camera/camera.cpp @@ -55,7 +55,7 @@ static esp_err_t stream_handler(httpd_req_t *req) } esp3d_camera.connect(true); #ifdef ESP_ACCESS_CONTROL_ALLOW_ORIGIN - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); #endif //ESP_ACCESS_CONTROL_ALLOw_ORIGIN camera_fb_t * fb = NULL; esp_err_t res = ESP_OK; diff --git a/esp3d/src/modules/filesystem/esp_filesystem.cpp b/esp3d/src/modules/filesystem/esp_filesystem.cpp index 03df817f..aabfb869 100644 --- a/esp3d/src/modules/filesystem/esp_filesystem.cpp +++ b/esp3d/src/modules/filesystem/esp_filesystem.cpp @@ -18,6 +18,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "../../include/esp3d_config.h" +#ifdef FILESYSTEM_FEATURE #include "esp_filesystem.h" #include "../../core/genLinkedList.h" #ifdef FILESYSTEM_TIMESTAMP_FEATURE @@ -215,3 +216,5 @@ ESP_File& ESP_File::operator=(const ESP_File & other) #endif //FILESYSTEM_TIMESTAMP_FEATURE return *this; } + +#endif //FILESYSTEM_FEATURE diff --git a/esp3d/src/modules/filesystem/esp_filesystem.h b/esp3d/src/modules/filesystem/esp_filesystem.h index 055774b8..3a0ae769 100644 --- a/esp3d/src/modules/filesystem/esp_filesystem.h +++ b/esp3d/src/modules/filesystem/esp_filesystem.h @@ -28,6 +28,8 @@ #define ESP_FILE_WRITE 1 #define ESP_FILE_APPEND 2 +#define ESP_FLASH_FS_HEADER "/FS:" + #define ESP_MAX_OPENHANDLE 4 class ESP_File diff --git a/esp3d/src/modules/gcode_host/gcode_host.cpp b/esp3d/src/modules/gcode_host/gcode_host.cpp index 3558e03d..97668965 100644 --- a/esp3d/src/modules/gcode_host/gcode_host.cpp +++ b/esp3d/src/modules/gcode_host/gcode_host.cpp @@ -22,7 +22,9 @@ #ifdef ESP_GCODE_HOST_FEATURE #include "gcode_host.h" #include "../../core/settings_esp3d.h" +#include "../../core/commands.h" #include "../serial/serial_service.h" +#include "../filesystem/esp_filesystem.h" GcodeHost esp3d_gcode_host; @@ -54,104 +56,111 @@ void GcodeHost::handle() { } -uint8_t GcodeHost::Checksum(const char * command, uint16_t commandSize) +uint8_t GcodeHost::Checksum(const char * command, uint32_t commandSize) { uint8_t checksum_val =0; - if (command == NULL) return 0; - for (uint16_t i=0; i < commandSize; i++) - { - checksum_val = checksum_val ^ ((uint8_t)command[i]); - } + if (command == NULL) { + return 0; + } + for (uint32_t i=0; i < commandSize; i++) { + checksum_val = checksum_val ^ ((uint8_t)command[i]); + } return checksum_val; } -String GcodeHost::CheckSumCommand(const char* command, uint16_t commandnb){ - String commandchecksum = "N" + String((uint16_t)commandnb)+ " " + command; +String GcodeHost::CheckSumCommand(const char* command, uint32_t commandnb) +{ + String commandchecksum = "N" + String((uint32_t)commandnb)+ " " + command; uint8_t crc = Checksum(commandchecksum.c_str(), commandchecksum.length()); commandchecksum+="*"+String(crc); return commandchecksum; } -size_t GcodeHost::wait_for_data(uint32_t timeout){ +size_t GcodeHost::wait_for_data(uint32_t timeout) +{ uint32_t start = millis(); - while ((serial_service.available() < 2) && ((millis()-start) < timeout)) - { - Hal::wait (0); //minimum delay is 10 actually - } + while ((serial_service.available() < 2) && ((millis()-start) < timeout)) { + Hal::wait (0); //minimum delay is 10 actually + } return serial_service.available(); } -bool GcodeHost::resetCommandNumbering(){ +bool GcodeHost::resetCommandNumbering() +{ String resetcmd = "M110 N0"; - if (Settings_ESP3D::GetFirmwareTarget() == SMOOTHIEWARE)resetcmd = "N0 M110"; - else resetcmd = "M110 N0"; + if (Settings_ESP3D::GetFirmwareTarget() == SMOOTHIEWARE) { + resetcmd = "N0 M110"; + } else { + resetcmd = "M110 N0"; + } _commandnumber = 1; return sendCommand(resetcmd.c_str()); } /*bool GcodeHost::endUpload(){ - + return true; }*/ -bool GcodeHost::wait_for_ack(uint32_t timeout, bool checksum, const char * ack){ +bool GcodeHost::wait_for_ack(uint32_t timeout, bool checksum, const char * ack) +{ _needcommandnumber = _commandnumber; uint32_t start = millis(); String answer = ""; - while ((millis()-start) < timeout) - { - size_t len = serial_service.available(); - if (len > 0){ - uint8_t * sbuf = (uint8_t *)malloc(len+1); - if(!sbuf){ - _error = ERROR_MEMORY_PROBLEM; - return false; + while ((millis()-start) < timeout) { + size_t len = serial_service.available(); + if (len > 0) { + uint8_t * sbuf = (uint8_t *)malloc(len+1); + if(!sbuf) { + _error = ERROR_MEMORY_PROBLEM; + return false; + } + sbuf[len] = '\0'; + answer+= (const char *)sbuf; + free(sbuf); + log_esp3d("Answer: %s",answer.c_str()); + //check for ack + if (ack!=nullptr) { + if (answer.indexOf(ack) != -1) { + _error = ERROR_NO_ERROR; + return true; } - sbuf[len] = '\0'; - answer+= (const char *)sbuf; - free(sbuf); - log_esp3d("Answer: %s",anwer.c_str()); - //check for ack - if (ack!=nullptr){ - if (answer.indexOf(ack) != -1){ - _error = ERROR_NO_ERROR; - return true; - } - } else{ - if (answer.indexOf("ok") != -1){ - if (!checksum){ - _error = ERROR_NO_ERROR; - return true; - } else{ - //check number - String ackstring = "ok " + String(_commandnumber); - if (answer.indexOf(ackstring) != -1){ - _error = ERROR_NO_ERROR; - return true; - } + } else { + //wait is not an ack as it can appear any time + if (answer.indexOf("ok") != -1) { + if (!checksum) { + _error = ERROR_NO_ERROR; + return true; + } else { + //check number + String ackstring = "ok " + String(_commandnumber); + if (answer.indexOf(ackstring) != -1) { + _error = ERROR_NO_ERROR; + return true; } } } - //check for error - if ((answer.indexOf("Resend:") != -1) || (answer.indexOf("rs N") != -1)){ - _needcommandnumber = Get_commandNumber(answer); - if (_needcommandnumber == _commandnumber) { - _error = ERROR_RESEND; - } else { - _error = ERROR_NUMBER_MISMATCH; - log_esp3d("Error provived %d but need %d", _commandnumber, _needcommandnumber); - } - - return false; - } - if (answer.indexOf("skip") != -1){ - _error = ERROR_LINE_IGNORED; - return false; - } } - - Hal::wait (0); //minimum delay is 10 actually + //check for error + if ((answer.indexOf("Resend:") != -1) || (answer.indexOf("rs N") != -1)) { + _needcommandnumber = Get_commandNumber(answer); + if (_needcommandnumber == _commandnumber) { + _error = ERROR_RESEND; + } else { + _error = ERROR_NUMBER_MISMATCH; + log_esp3d("Error provived %d but need %d", _commandnumber, _needcommandnumber); + } + + return false; + } + if (answer.indexOf("skip") != -1) { + _error = ERROR_LINE_IGNORED; + return false; + } } + + Hal::wait (0); //minimum delay is 10 actually + } _error = ERROR_ACK_NUMBER; return false; } @@ -161,18 +170,19 @@ bool GcodeHost::wait_for_ack(uint32_t timeout, bool checksum, const char * ack){ //others error cancel the sending //number mismatch / skip / timeout error must be managed out of this function //line number incrementation is not done in this function neither -bool GcodeHost::sendCommand(const char* command, bool checksum, bool wait4ack, const char * ack){ +bool GcodeHost::sendCommand(const char* command, bool checksum, bool wait4ack, const char * ack) +{ log_esp3d("Send command: %s", command); String s; - if(checksum){ + if(checksum) { s = CheckSumCommand(command, _commandnumber); - } else{ - s = command; + } else { + s = command; } for(uint8_t try_nb = 0; try_nb < MAX_TRY_2_SEND; try_nb ++) { _error = ERROR_NO_ERROR; purge(); - if ((_error != ERROR_NO_ERROR) && wait4ack){ + if ((_error != ERROR_NO_ERROR) && wait4ack) { return false; } else { //if no need to wait for ack the purge has no real impact but clear buffer @@ -182,53 +192,54 @@ bool GcodeHost::sendCommand(const char* command, bool checksum, bool wait4ack, c //to give a chance to not overload buffer bool done = false; while (((millis() - start) < DEFAULT_TIMOUT) && !done) { - if (serial_service.availableForWrite() > s.length()){ + if (serial_service.availableForWrite() > s.length()) { if (strlen(command) == serial_service.write((const uint8_t*)s.c_str(), s.length())) { - if (serial_service.write('\n')==1){ - if(!wait4ack){ + if (serial_service.write('\n')==1) { + if(!wait4ack) { log_esp3d("No need ack"); return true; } - //process answer - if (wait_for_ack(DEFAULT_TIMOUT, ack)) { + //process answer + if (wait_for_ack(DEFAULT_TIMOUT, ack)) { log_esp3d("Command got ack"); - return true; - } else { - //what is the error ? - log_esp3d("Error: %d", _error); - //no need to retry for this one - if (_error == ERROR_MEMORY_PROBLEM) { - return false; - } - //need to resend command - if (_error == ERROR_RESEND) { - done = true; - } - //the printer ask for another command line so exit - if ((_error == ERROR_NUMBER_MISMATCH) || (_error == ERROR_LINE_IGNORED)){ - return false; - } - } + return true; + } else { + //what is the error ? + log_esp3d("Error: %d", _error); + //no need to retry for this one + if (_error == ERROR_MEMORY_PROBLEM) { + return false; + } + //need to resend command + if (_error == ERROR_RESEND) { + done = true; + } + //the printer ask for another command line so exit + if ((_error == ERROR_NUMBER_MISMATCH) || (_error == ERROR_LINE_IGNORED)) { + return false; + } + } } } } } } if (_error == ERROR_NO_ERROR) { - _error = ERROR_CANNOT_SEND_DATA; + _error = ERROR_CANNOT_SEND_DATA; log_esp3d("Error: %d", _error); } return false; } -bool GcodeHost::purge(uint32_t timeout){ +bool GcodeHost::purge(uint32_t timeout) +{ uint32_t start = millis(); uint8_t buf [51]; _error = 0; - log_esp3d("Purge started") - while (serial_service.available() > 0){ + log_esp3d("Purge started"); + while (serial_service.available() > 0) { if ((millis() - start ) > timeout) { - log_esp3d("Purge timeout\r\n") + log_esp3d("Purge timeout\r\n"); _error = ERROR_TIME_OUT; return false; } @@ -238,33 +249,105 @@ bool GcodeHost::purge(uint32_t timeout){ if ( (Settings_ESP3D::GetFirmwareTarget() == REPETIER4DV) || (Settings_ESP3D::GetFirmwareTarget() == REPETIER) || _waitwhenidle) { String s = (const char *)buf; //repetier never stop sending data so no need to wait if have 'wait' or 'busy' - if((s.indexOf ("wait") > -1) || (s.indexOf ("busy") > -1))return true; - log_esp3d("Impossible to purge\r\n") + if((s.indexOf ("wait") > -1) || (s.indexOf ("busy") > -1)) { + return true; + } + log_esp3d("Impossible to purge\r\n"); } Hal::wait (0); - } - log_esp3d("Purge done") - return true; + } + log_esp3d("Purge done"); + return true; } -uint16_t GcodeHost::Get_commandNumber(String & response){ - int64_t l = 0; +uint32_t GcodeHost::Get_commandNumber(String & response) +{ + uint32_t l = 0; String sresend = "Resend:"; - if ( Settings_ESP3D::GetFirmwareTarget() == SMOOTHIEWARE){ + if ( Settings_ESP3D::GetFirmwareTarget() == SMOOTHIEWARE) { sresend = "rs N"; } int pos = response.indexOf(sresend); if (pos == -1 ) { log_esp3d("Cannot find label", _error); return -1; - } + } pos+=sresend.length(); int pos2 = response.indexOf("\n", pos); String snum = response.substring(pos, pos2); //remove potential unwished char snum.replace("\r", ""); l = snum.toInt(); - log_esp3d("Command number to resend is %s", String(l).c_str()); + log_esp3d("Command number to resend is %s", String((uint32_t)l).c_str()); return l; } + +bool GcodeHost::processFSFile(const char * filename, level_authenticate_type auth_type, ESP3DOutput * output) +{ + bool res = true; + log_esp3d("Processing FS : %s", filename); + if (!ESP_FileSystem::exists(filename)) { + log_esp3d("Cannot find file"); + return false; + } + ESP_File f = ESP_FileSystem::open(filename); + if (!f.isOpen()) { + log_esp3d("Cannot open file"); + return false; + } + size_t filesize = f.size(); + int8_t ch; + String cmd = ""; + for (size_t c = 0; c< filesize ; c++) { + ch = f.read(); + if (ch == -1) { + log_esp3d("Error reading file"); + f.close(); + return false; + } + if ((ch == 13)||(ch == 10) || (c==(filesize-1))) { + //for end of file without \n neither \r + if (!((ch == 13)||(ch == 10)) && (c==(filesize-1))) { + cmd+=(char)ch; + } + cmd.trim(); + if(cmd.length() > 0) { + //ignore comments + if (cmd[0]!=';') { + //it is internal or not ? + if(esp3d_commands.is_esp_command((uint8_t *)cmd.c_str(), cmd.length())) { + esp3d_commands.process((uint8_t *)cmd.c_str(), cmd.length(), output, auth_type); + } else { + if (!sendCommand(cmd.c_str(),false, true)) { + log_esp3d("Error sending command"); + //To stop instead of continue may need some trigger + } + } + } + cmd=""; + } + + } else { + cmd+=(char)ch; + } + } + f.close(); + return res; +} + +bool GcodeHost::processFile(const char * filename, level_authenticate_type auth_type, ESP3DOutput * output) +{ + String FileName = filename; + FileName.trim(); + log_esp3d("Processing: %s", FileName.c_str()); + if (FileName.startsWith(ESP_FLASH_FS_HEADER)) { + String f = FileName.substring(strlen(ESP_FLASH_FS_HEADER),FileName.length()); + return processFSFile(f.c_str(), auth_type, output); + } + //TODO SD = SDCard + //TODO UD = USB DISK + log_esp3d("Invalid filename"); + return false; +} + #endif //ESP_GCODE_HOST_FEATURE diff --git a/esp3d/src/modules/gcode_host/gcode_host.h b/esp3d/src/modules/gcode_host/gcode_host.h index 2cea929e..84d62bd2 100644 --- a/esp3d/src/modules/gcode_host/gcode_host.h +++ b/esp3d/src/modules/gcode_host/gcode_host.h @@ -23,6 +23,10 @@ #ifndef _GCODE_HOST_H #define _GCODE_HOST_H +#include +#include "../authentication/authentication_service.h" +class ESP3DOutput; + #define DEFAULT_TIMOUT 2000 #define MAX_TRY_2_SEND 5 #define ERROR_NO_ERROR 0 @@ -44,20 +48,34 @@ public: void end(); void handle(); bool sendCommand(const char* command, bool checksum = false, bool wait4ack = true, const char * ack=nullptr); - uint16_t currentCommandNumber(){return _commandnumber;} - void setCommandNumber(uint16_t n){_commandnumber = n;} + uint32_t currentCommandNumber() + { + return _commandnumber; + } + void setCommandNumber(uint32_t n) + { + _commandnumber = n; + } bool resetCommandNumbering(); - uint8_t Checksum(const char * command, uint16_t commandSize); - String CheckSumCommand(const char* command, uint16_t commandnb); + uint8_t Checksum(const char * command, uint32_t commandSize); + String CheckSumCommand(const char* command, uint32_t commandnb); size_t wait_for_data(uint32_t timeout = DEFAULT_TIMOUT); bool wait_for_ack(uint32_t timeout = DEFAULT_TIMOUT, bool checksum=false, const char * ack=nullptr); bool purge(uint32_t timeout = DEFAULT_TIMOUT); - uint16_t Get_commandNumber(String & response); - bool waitWhenIdle(){ return _waitwhenidle;} - uint8_t getErrorNum(){ return _error;} + uint32_t Get_commandNumber(String & response); + bool waitWhenIdle() + { + return _waitwhenidle; + } + uint8_t getErrorNum() + { + return _error; + } + bool processFile(const char * filename, level_authenticate_type auth_type, ESP3DOutput * output); + bool processFSFile(const char * filename, level_authenticate_type auth_type, ESP3DOutput * output); private: - uint16_t _commandnumber; - uint16_t _needcommandnumber; + uint32_t _commandnumber; + uint32_t _needcommandnumber; bool _waitwhenidle; uint8_t _error; };