From 3a6c216ffd26455b174fd149c7dbfe51ff59ecd4 Mon Sep 17 00:00:00 2001 From: Luc <8822552+luc-github@users.noreply.github.com> Date: Sat, 7 Dec 2024 20:20:18 +0800 Subject: [PATCH] Refactorize Serial service code to avoid redondant code between esp32 and esp8266 Implement isrealtimeCommand check for serial and centralize function in string helper Add new type message : realtimecmd Update simulator to handle commands and realtime commands Add simple serial test tool Generate error if use HAS_DISPLAY with grbl/grblHAL --- esp3d/configuration.h | 8 +- esp3d/src/core/esp3d.cpp | 2 +- esp3d/src/core/esp3d_commands.cpp | 19 +- esp3d/src/core/esp3d_commands.h | 1 - esp3d/src/core/esp3d_message.h | 2 +- esp3d/src/core/esp3d_string.cpp | 4 +- esp3d/src/core/esp3d_string.h | 2 +- .../modules/http/handlers/handle-command.cpp | 34 +-- esp3d/src/modules/http/http_server.cpp | 3 +- esp3d/src/modules/serial/serial_service.cpp | 176 ++++++++++++ esp3d/src/modules/serial/serial_service.h | 9 +- .../modules/serial/serial_service_esp32.cpp | 266 +++--------------- .../modules/serial/serial_service_esp8266.cpp | 196 ++----------- tools/fw_simulator/fw_simulator.py | 70 ++++- tools/fw_simulator/grblhal.py | 231 +++++++++++++++ tools/serial_test/serial_test.py | 33 +++ 16 files changed, 614 insertions(+), 442 deletions(-) create mode 100644 esp3d/src/modules/serial/serial_service.cpp create mode 100644 tools/fw_simulator/grblhal.py create mode 100644 tools/serial_test/serial_test.py diff --git a/esp3d/configuration.h b/esp3d/configuration.h index 5a3e5d20..0b429f24 100644 --- a/esp3d/configuration.h +++ b/esp3d/configuration.h @@ -443,7 +443,7 @@ /* Printer screen * If your printer has a display */ -#define PRINTER_HAS_DISPLAY +//#define PRINTER_HAS_DISPLAY /* ESP3D screen * Screen connected to ESP board @@ -644,9 +644,9 @@ // LOG_OUTPUT_SERIAL2 // LOG_OUTPUT_TELNET // LOG_OUTPUT_WEBSOCKET -// #define ESP_LOG_FEATURE LOG_OUTPUT_SERIAL0 + #define ESP_LOG_FEATURE LOG_OUTPUT_SERIAL0 -// #define ESP3D_DEBUG_LEVEL LOG_LEVEL_DEBUG + #define ESP3D_DEBUG_LEVEL LOG_LEVEL_DEBUG #ifdef ESP_LOG_FEATURE #define LOG_ESP3D_BAUDRATE 115200 @@ -657,7 +657,7 @@ // #define ESP_BENCHMARK_FEATURE // Disable sanity check at compilation -// #define ESP_NO_SANITY_CHECK + #define ESP_NO_SANITY_CHECK /************************************ * diff --git a/esp3d/src/core/esp3d.cpp b/esp3d/src/core/esp3d.cpp index b115b9fe..68265134 100644 --- a/esp3d/src/core/esp3d.cpp +++ b/esp3d/src/core/esp3d.cpp @@ -278,7 +278,7 @@ void Esp3D::restart_now() { #if defined(FILESYSTEM_FEATURE) ESP_FileSystem::end(); #endif // FILESYSTEM_FEATURE -#if COMMUNICATION_PROTOCOL == RAW_SERIAL || COMMUNICATION_PROTOCOL == MKS_SERIAL +#if (COMMUNICATION_PROTOCOL == RAW_SERIAL || COMMUNICATION_PROTOCOL == MKS_SERIAL) & defined(ARDUINO_ARCH_ESP8266) esp3d_serial_service.swap(); #endif // COMMUNICATION_PROTOCOL == RAW_SERIAL || COMMUNICATION_PROTOCOL == // MKS_SERIAL diff --git a/esp3d/src/core/esp3d_commands.cpp b/esp3d/src/core/esp3d_commands.cpp index 9bafe2ba..80d0ab94 100644 --- a/esp3d/src/core/esp3d_commands.cpp +++ b/esp3d/src/core/esp3d_commands.cpp @@ -107,8 +107,6 @@ ESP3DCommands::ESP3DCommands() { ESP3DCommands::~ESP3DCommands() {} -bool ESP3DCommands::isRealTimeCommand(char *cmd, size_t len) { return false; } - // check if current line is an [ESPXXX] command bool ESP3DCommands::is_esp_command(uint8_t *sbuf, size_t len) { // TODO @@ -1156,10 +1154,6 @@ bool ESP3DCommands::dispatchIdValue(bool json, const char *Id, } bool ESP3DCommands::formatCommand(char *cmd, size_t len) { - if (isRealTimeCommand(cmd, len)) { - // TODO: what if is realtime command ? - return true; - } uint sizestr = strlen(cmd); if (len > sizestr + 2) { cmd[sizestr] = '\n'; @@ -1233,7 +1227,7 @@ bool ESP3DCommands::dispatch(ESP3DMessage *msg, uint8_t *sbuf, size_t len) { // check is need \n at the end of the command if (msg->type == ESP3DMessageType::unique || msg->type == ESP3DMessageType::tail) { - esp3d_log("unique or tail message :*%s*", (char *)sbuf); + esp3d_log_d("unique or tail message :*%s*", (char *)sbuf); if (!formatCommand((char *)sbuf, len)) { esp3d_log("format command failed"); String tmpstr = ""; @@ -1250,7 +1244,7 @@ bool ESP3DCommands::dispatch(ESP3DMessage *msg, uint8_t *sbuf, size_t len) { return false; } } else { - esp3d_log("format command success, no need to update"); + esp3d_log_d("format command success, no need to update"); if (!esp3d_message_manager.setDataContent(msg, sbuf, len)) { esp3d_log_e("set data content failed"); esp3d_message_manager.deleteMsg(msg); @@ -1259,6 +1253,9 @@ bool ESP3DCommands::dispatch(ESP3DMessage *msg, uint8_t *sbuf, size_t len) { } } else { esp3d_log("not unique or tail message"); + if (msg->type == ESP3DMessageType::realtimecmd){ + esp3d_log_d("realtime command"); + } if (!esp3d_message_manager.setDataContent(msg, sbuf, len)) { esp3d_log_e("set data content failed"); esp3d_message_manager.deleteMsg(msg); @@ -1468,6 +1465,12 @@ bool ESP3DCommands::dispatch(ESP3DMessage *msg) { #ifdef PRINTER_HAS_DISPLAY case ESP3DClientType::remote_screen: + if (ESP3DSettings::GetFirmwareTarget() == GRBL || + ESP3DSettings::GetFirmwareTarget() == GRBLHAL) { + esp3d_log_e("Remote screen message is not supported for GRBL"); + sendOk = false; + break; + } esp3d_log("Remote screen message"); // change target to output client msg->target = getOutputClient(); diff --git a/esp3d/src/core/esp3d_commands.h b/esp3d/src/core/esp3d_commands.h index c46e3625..3925b957 100644 --- a/esp3d/src/core/esp3d_commands.h +++ b/esp3d/src/core/esp3d_commands.h @@ -227,7 +227,6 @@ class ESP3DCommands { bool isFirst = false); bool dispatchAuthenticationError(ESP3DMessage* msg, uint cmdid, bool json); bool formatCommand(char* cmd, size_t len); - bool isRealTimeCommand(char* cmd, size_t len); ESP3DClientType getOutputClient(bool fromSettings = false); void setOutputClient(ESP3DClientType output_client) { _output_client = output_client; diff --git a/esp3d/src/core/esp3d_message.h b/esp3d/src/core/esp3d_message.h index d0d081ec..a921ae8f 100644 --- a/esp3d/src/core/esp3d_message.h +++ b/esp3d/src/core/esp3d_message.h @@ -60,7 +60,7 @@ class WebServer; #endif //pdTRUE #endif //ESP8266 -enum class ESP3DMessageType : uint8_t { head, core, tail, unique }; +enum class ESP3DMessageType : uint8_t { head, core, tail, unique, realtimecmd }; union ESP3DRequest { uint id; diff --git a/esp3d/src/core/esp3d_string.cpp b/esp3d/src/core/esp3d_string.cpp index 18e9b2e5..2d64aaf1 100644 --- a/esp3d/src/core/esp3d_string.cpp +++ b/esp3d/src/core/esp3d_string.cpp @@ -175,7 +175,7 @@ const char* esp3d_string::urlEncode(const char* s) { static String encoded; encoded = ""; char temp[4]; - for (int i = 0; i < strlen(s); i++) { + for (size_t i = 0; i < strlen(s); i++) { temp[0] = s[i]; if (temp[0] == 32) { // space encoded.concat('+'); @@ -267,7 +267,7 @@ const char* esp3d_string::formatDuration(uint64_t duration) { return result.c_str(); } -bool esp3d_string::isRealtimeCommand(char c) { +bool esp3d_string::isRealTimeCommand(char c) { if (ESP3DSettings::GetFirmwareTarget() == GRBL || ESP3DSettings::GetFirmwareTarget() == GRBLHAL) { // Standard characters diff --git a/esp3d/src/core/esp3d_string.h b/esp3d/src/core/esp3d_string.h index 3f8c739d..c96f03e2 100644 --- a/esp3d/src/core/esp3d_string.h +++ b/esp3d/src/core/esp3d_string.h @@ -31,7 +31,7 @@ const char* formatBytes(uint64_t bytes); bool isPrintableChar(char c); const char* expandString(const char* s, bool formatspace = false); const char * urlEncode(const char* s); -bool isRealtimeCommand(char c); +bool isRealTimeCommand(char c); } // namespace esp3d_string #endif //_ESP3D_STRING_H diff --git a/esp3d/src/modules/http/handlers/handle-command.cpp b/esp3d/src/modules/http/handlers/handle-command.cpp index e844b0ac..96db9d64 100644 --- a/esp3d/src/modules/http/handlers/handle-command.cpp +++ b/esp3d/src/modules/http/handlers/handle-command.cpp @@ -29,19 +29,9 @@ #include "../../../core/esp3d_commands.h" #include "../../../core/esp3d_message.h" #include "../../../core/esp3d_settings.h" +#include "../../../core/esp3d_string.h" #include "../../authentication/authentication_service.h" -const unsigned char realTimeCommands[] = { - '!', '~', '?', 0x18, 0x84, 0x85, 0x90, 0x92, 0x93, 0x94, 0x95, - 0x96, 0x97, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0xA0, 0xA1}; -bool isRealTimeCommand(unsigned char c) { - for (unsigned int i = 0; i < sizeof(realTimeCommands); i++) { - if (c == realTimeCommands[i]) { - return true; - } - } - return false; -} // Handle web command query and send answer////////////////////////////// void HTTP_Server::handle_web_command() { @@ -53,26 +43,36 @@ void HTTP_Server::handle_web_command() { } // esp3d_log("Authentication = %d", auth_level); String cmd = ""; + bool isRealTimeCommand = false; if (_webserver->hasArg("cmd")) { cmd = _webserver->arg("cmd"); + esp3d_log_d("Command is %s", cmd.c_str()); if (!cmd.endsWith("\n")) { - if (ESP3DSettings::GetFirmwareTarget() == GRBL) { + esp3d_log_d("Command is not ending with \\n"); + if (ESP3DSettings::GetFirmwareTarget() == GRBL || ESP3DSettings::GetFirmwareTarget() == GRBLHAL) { uint len = cmd.length(); - if (!((len == 1 && isRealTimeCommand(cmd[0])) || - (len == 2 && isRealTimeCommand(cmd[1])))) { + if (!((len == 1 && esp3d_string::isRealTimeCommand(cmd[0])) || + (len == 2 && esp3d_string::isRealTimeCommand(cmd[1])))) { cmd += "\n"; + esp3d_log_d("Command is not realtime, adding \\n"); } else { // no need \n for realtime command + esp3d_log_d("Command is realtime, no need to add \\n"); + isRealTimeCommand = true; // remove the 0XC2 that should not be there - if (len == 2 && isRealTimeCommand(cmd[1]) && cmd[1] == 0xC2) { + if (len == 2 && esp3d_string::isRealTimeCommand(cmd[1]) && cmd[1] == 0xC2) { cmd[0] = cmd[1]; cmd[1] = 0x0; + esp3d_log_d("Command is realtime, removing 0xC2"); } } } else { + esp3d_log_d("Command is not realtime, adding \\n"); cmd += "\n"; // need to validate command } + } else { + esp3d_log_d("Command is ending with \\n"); } - esp3d_log("Web Command: %s", cmd.c_str()); + esp3d_log_d("Message type is %s for %s", isRealTimeCommand ? "realtimecmd" : "unique", cmd.c_str()); if (esp3d_commands.is_esp_command((uint8_t *)cmd.c_str(), cmd.length())) { ESP3DMessage *msg = esp3d_message_manager.newMsg( ESP3DClientType::http, esp3d_commands.getOutputClient(), @@ -91,7 +91,7 @@ void HTTP_Server::handle_web_command() { // no need to wait to answer then _webserver->send(200, "text/plain", "ESP3D says: command forwarded"); esp3d_commands.dispatch(cmd.c_str(), esp3d_commands.getOutputClient(), - no_id, ESP3DMessageType::unique, + no_id, isRealTimeCommand ? ESP3DMessageType::realtimecmd :ESP3DMessageType::unique, ESP3DClientType::http, auth_level); } } else if (_webserver->hasArg("ping")) { diff --git a/esp3d/src/modules/http/http_server.cpp b/esp3d/src/modules/http/http_server.cpp index 08299927..e8ab3763 100644 --- a/esp3d/src/modules/http/http_server.cpp +++ b/esp3d/src/modules/http/http_server.cpp @@ -257,7 +257,8 @@ bool HTTP_Server::dispatch(ESP3DMessage* msg) { } if ((msg->size > 0 && msg->data) || (msg->type == ESP3DMessageType::tail)) { if (msg->type == ESP3DMessageType::head || - msg->type == ESP3DMessageType::unique) { + msg->type == ESP3DMessageType::unique || + msg->type == ESP3DMessageType::realtimecmd) { set_http_headers(); int code = 200; if (msg->request_id.code != 0) { diff --git a/esp3d/src/modules/serial/serial_service.cpp b/esp3d/src/modules/serial/serial_service.cpp new file mode 100644 index 00000000..4d965a53 --- /dev/null +++ b/esp3d/src/modules/serial/serial_service.cpp @@ -0,0 +1,176 @@ +/* + esp3d_serial_service.cpp - serial services functions class + + Copyright (c) 2014 Luc Lebosse. All rights reserved. + + This code 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 code 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 code; 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 COMMUNICATION_PROTOCOL == RAW_SERIAL || \ + defined(ESP_SERIAL_BRIDGE_OUTPUT) || COMMUNICATION_PROTOCOL == MKS_SERIAL +#include "../../core/esp3d_commands.h" +#include "../../core/esp3d_settings.h" +#include "../../core/esp3d_string.h" +#include "../authentication/authentication_service.h" +#include "serial_service.h" + +extern HardwareSerial *Serials[]; + +// Serial Parameters + +ESP3DSerialService esp3d_serial_service = ESP3DSerialService(MAIN_SERIAL); +#if defined(ESP_SERIAL_BRIDGE_OUTPUT) +ESP3DSerialService serial_bridge_service = ESP3DSerialService(BRIDGE_SERIAL); +#endif // ESP_SERIAL_BRIDGE_OUTPUT + +const uint32_t SupportedBaudList[] = {9600, 19200, 38400, 57600, 74880, + 115200, 230400, 250000, 500000, 921600, + 1000000, 1958400, 2000000}; +const size_t SupportedBaudListSize = + sizeof(SupportedBaudList) / sizeof(uint32_t); + + + +// Destructor +ESP3DSerialService::~ESP3DSerialService() { end(); } + +// extra parameters that do not need a begin +void ESP3DSerialService::setParameters() { +#if defined(AUTHENTICATION_FEATURE) + _needauthentication = + (ESP3DSettings::readByte(ESP_SECURE_SERIAL) == 0) ? false : true; +#else + _needauthentication = false; +#endif // AUTHENTICATION_FEATURE +} + +void ESP3DSerialService::initAuthentication() { +#if defined(AUTHENTICATION_FEATURE) + _auth = ESP3DAuthenticationLevel::guest; +#else + _auth = ESP3DAuthenticationLevel::admin; +#endif // AUTHENTICATION_FEATURE +} +ESP3DAuthenticationLevel ESP3DSerialService::getAuthentication() { + if (_needauthentication) { + return _auth; + } + return ESP3DAuthenticationLevel::admin; +} + +// return the array of uint32_t and array size +const uint32_t *ESP3DSerialService::get_baudratelist(uint8_t *count) { + if (count) { + *count = sizeof(SupportedBaudList) / sizeof(uint32_t); + } + return SupportedBaudList; +} + + + + +void ESP3DSerialService::flushChar(char c) { flushData((uint8_t *)&c, 1, ESP3DMessageType::realtimecmd); } + +void ESP3DSerialService::flushBuffer() { + _buffer[_buffer_size] = 0x0; + flushData((uint8_t *)_buffer, _buffer_size, ESP3DMessageType::unique); + _buffer_size = 0; +} + + +void ESP3DSerialService::updateBaudRate(uint32_t br) { + if (br != _baudRate) { + Serials[_serialIndex]->flush(); + Serials[_serialIndex]->updateBaudRate(br); + _baudRate = br; + } +} + +// Get current baud rate +uint32_t ESP3DSerialService::baudRate() { return _baudRate; } + +size_t ESP3DSerialService::writeBytes(const uint8_t *buffer, size_t size) { + if (!_started) { + return 0; + } + if ((uint)Serials[_serialIndex]->availableForWrite() >= size) { + return Serials[_serialIndex]->write(buffer, size); + } else { + size_t sizetosend = size; + size_t sizesent = 0; + uint8_t *buffertmp = (uint8_t *)buffer; + uint32_t starttime = millis(); + // loop until all is sent or timeout + while (sizetosend > 0 && ((millis() - starttime) < 100)) { + size_t available = Serials[_serialIndex]->availableForWrite(); + if (available > 0) { + // in case less is sent + available = Serials[_serialIndex]->write( + &buffertmp[sizesent], + (available >= sizetosend) ? sizetosend : available); + sizetosend -= available; + sizesent += available; + starttime = millis(); + } else { + ESP3DHal::wait(5); + } + } + return sizesent; + } +} + +size_t ESP3DSerialService::readBytes(uint8_t *sbuf, size_t len) { + if (!_started) { + return -1; + } + return Serials[_serialIndex]->readBytes(sbuf, len); +} + +void ESP3DSerialService::flush() { + if (!_started) { + return; + } + Serials[_serialIndex]->flush(); +} + + +bool ESP3DSerialService::dispatch(ESP3DMessage *message) { + bool done = false; + // Only is serial service is started + if (_started) { + // Only if message is not null + if (message) { + // if message is not null + if (message->data && message->size != 0) { + if (writeBytes(message->data, message->size) == message->size) { + flush(); + // Delete message now + esp3d_message_manager.deleteMsg(message); + done = true; + } else { + esp3d_log_e("Error while sending data"); + } + } else { + esp3d_log_e("Error null data"); + } + } else { + esp3d_log_e("Error null message"); + } + } + return done; +} + +#endif // COMMUNICATION_PROTOCOL == RAW_SERIAL || + // defined(ESP_SERIAL_BRIDGE_OUTPUT) \ No newline at end of file diff --git a/esp3d/src/modules/serial/serial_service.h b/esp3d/src/modules/serial/serial_service.h index 3cf39609..cfd85242 100644 --- a/esp3d/src/modules/serial/serial_service.h +++ b/esp3d/src/modules/serial/serial_service.h @@ -29,6 +29,7 @@ #endif // ARDUINO_ARCH_ESP32 #define ESP3D_SERIAL_BUFFER_SIZE 1024 +#define ESP_SERIAL_PARAM SERIAL_8N1 extern const uint32_t SupportedBaudList[]; extern const size_t SupportedBaudListSize; @@ -47,7 +48,9 @@ class ESP3DSerialService final { uint8_t serialIndex() { return _serialIndex; } const uint32_t *get_baudratelist(uint8_t *count); void flush(); + #if defined(ARDUINO_ARCH_ESP8266) void swap(); + #endif // ARDUINO_ARCH_ESP8266 size_t writeBytes(const uint8_t *buffer, size_t size); size_t readBytes(uint8_t *sbuf, size_t len); inline bool started() { return _started; } @@ -77,8 +80,12 @@ class ESP3DSerialService final { SemaphoreHandle_t _mutex; ESP3DMessageFIFO _messagesInFIFO; #endif // ARDUINO_ARCH_ESP32 +#if defined(ARDUINO_ARCH_ESP8266) void push2buffer(uint8_t *sbuf, size_t len); - void flushbuffer(); +#endif // ARDUINO_ARCH_ESP8266 + void flushBuffer(); + void flushChar(char c); + void flushData(const uint8_t* data, size_t size, ESP3DMessageType type); }; extern ESP3DSerialService esp3d_serial_service; diff --git a/esp3d/src/modules/serial/serial_service_esp32.cpp b/esp3d/src/modules/serial/serial_service_esp32.cpp index 9583fe3f..f541b432 100644 --- a/esp3d/src/modules/serial/serial_service_esp32.cpp +++ b/esp3d/src/modules/serial/serial_service_esp32.cpp @@ -19,7 +19,8 @@ */ #if defined(ARDUINO_ARCH_ESP32) #include "../../include/esp3d_config.h" -#if COMMUNICATION_PROTOCOL == RAW_SERIAL || defined(ESP_SERIAL_BRIDGE_OUTPUT) || COMMUNICATION_PROTOCOL == MKS_SERIAL +#if COMMUNICATION_PROTOCOL == RAW_SERIAL || \ + defined(ESP_SERIAL_BRIDGE_OUTPUT) || COMMUNICATION_PROTOCOL == MKS_SERIAL #include "../../core/esp3d_commands.h" #include "../../core/esp3d_settings.h" #include "../../core/esp3d_string.h" @@ -38,19 +39,7 @@ HardwareSerial *Serials[MAX_SERIAL] = {&Serial, &Serial1, &Serial2}; #endif // Serial Parameters -#define ESP_SERIAL_PARAM SERIAL_8N1 -ESP3DSerialService esp3d_serial_service = ESP3DSerialService(MAIN_SERIAL); -#if defined(ESP_SERIAL_BRIDGE_OUTPUT) -ESP3DSerialService serial_bridge_service = ESP3DSerialService(BRIDGE_SERIAL); -#endif // ESP_SERIAL_BRIDGE_OUTPUT - -const uint32_t SupportedBaudList[] = {9600, 19200, 38400, 57600, 74880, - 115200, 230400, 250000, 500000, 921600, - 1000000, 1958400, 2000000}; -const size_t SupportedBaudListSize = sizeof(SupportedBaudList) / sizeof(uint32_t); - -#define TIMEOUT_SERIAL_FLUSH 1500 // Constructor ESP3DSerialService::ESP3DSerialService(uint8_t id) { _buffer_size = 0; @@ -85,34 +74,6 @@ ESP3DSerialService::ESP3DSerialService(uint8_t id) { _messagesInFIFO.setMaxSize(0); // no limit _baudRate = 0; } - -// Destructor -ESP3DSerialService::~ESP3DSerialService() { end(); } - -// extra parameters that do not need a begin -void ESP3DSerialService::setParameters() { -#if defined(AUTHENTICATION_FEATURE) - _needauthentication = - (ESP3DSettings::readByte(ESP_SECURE_SERIAL) == 0) ? false : true; -#else - _needauthentication = false; -#endif // AUTHENTICATION_FEATURE -} - -void ESP3DSerialService::initAuthentication() { -#if defined(AUTHENTICATION_FEATURE) - _auth = ESP3DAuthenticationLevel::guest; -#else - _auth = ESP3DAuthenticationLevel::admin; -#endif // AUTHENTICATION_FEATURE -} -ESP3DAuthenticationLevel ESP3DSerialService::getAuthentication() { - if (_needauthentication) { - return _auth; - } - return ESP3DAuthenticationLevel::admin; -} - void ESP3DSerialService::receiveSerialCb() { esp3d_serial_service.receiveCb(); } #if defined(ESP_SERIAL_BRIDGE_OUTPUT) @@ -130,11 +91,16 @@ void ESP3DSerialService::receiveCb() { while ((millis() - now) < SERIAL_COMMUNICATION_TIMEOUT) { if (Serials[_serialIndex]->available()) { _buffer[_buffer_size] = Serials[_serialIndex]->read(); - _buffer_size++; now = millis(); - if (_buffer_size > ESP3D_SERIAL_BUFFER_SIZE || - _buffer[_buffer_size - 1] == '\n') { - flushbuffer(); + if (esp3d_string::isRealTimeCommand(_buffer[_buffer_size])) { + flushChar(_buffer[_buffer_size]); + _buffer[_buffer_size] = '\0'; //remove realtime command from buffer + } else { + _buffer_size++; + if (_buffer_size > ESP3D_SERIAL_BUFFER_SIZE || + _buffer[_buffer_size - 1] == '\n') { + flushBuffer(); + } } } } @@ -225,12 +191,21 @@ bool ESP3DSerialService::end() { return true; } -// return the array of uint32_t and array size -const uint32_t *ESP3DSerialService::get_baudratelist(uint8_t *count) { - if (count) { - *count = sizeof(SupportedBaudList) / sizeof(uint32_t); +void ESP3DSerialService::flushData(const uint8_t *data, size_t size, ESP3DMessageType type) { + ESP3DMessage *message = esp3d_message_manager.newMsg( + _origin, + _id == MAIN_SERIAL ? ESP3DClientType::all_clients + : esp3d_commands.getOutputClient(), + data, size, getAuthentication()); + + if (message) { + message->type = type; + esp3d_log("Message sent to fifo list"); + _messagesInFIFO.push(message); + } else { + esp3d_log_e("Cannot create message"); } - return SupportedBaudList; + _lastflush = millis(); } // Function which could be called in other loop @@ -254,179 +229,30 @@ void ESP3DSerialService::handle() { } } -void ESP3DSerialService::flushbuffer() { - _buffer[_buffer_size] = 0x0; - if (_buffer_size == 1 && _buffer[0] == '\n') { - _buffer_size = 0; - return; - } - - // dispatch command - ESP3DMessage *message = esp3d_message_manager.newMsg( - _origin, - _id == MAIN_SERIAL ? ESP3DClientType::all_clients - : esp3d_commands.getOutputClient(), - (uint8_t *)_buffer, _buffer_size, getAuthentication()); - if (message) { - // process command - message->type = ESP3DMessageType::unique; - esp3d_log("Message sent to fifo list"); - _messagesInFIFO.push(message); - } else { - esp3d_log_e("Cannot create message"); - } - _lastflush = millis(); - _buffer_size = 0; -} - -// push collected data to buffer and proceed accordingly -void ESP3DSerialService::push2buffer(uint8_t *sbuf, size_t len) { - /* if (!_started) { - return; - } - esp3d_log("buffer get %d data ", len); - for (size_t i = 0; i < len; i++) { - _lastflush = millis(); - // command is defined - if (char(sbuf[i]) == '\n') { - if (_buffer_size < ESP3D_SERIAL_BUFFER_SIZE) { - _buffer[_buffer_size] = sbuf[i]; - _buffer_size++; - } - flushbuffer(); - } else if (esp3d_string::isPrintableChar(char(sbuf[i]))) { - if (_buffer_size < ESP3D_SERIAL_BUFFER_SIZE) { - _buffer[_buffer_size] = sbuf[i]; - _buffer_size++; - } else { - flushbuffer(); - _buffer[_buffer_size] = sbuf[i]; - _buffer_size++; - } - } else { // it is not printable char - // clean buffer first - if (_buffer_size > 0) { - flushbuffer(); - } - // process char - _buffer[_buffer_size] = sbuf[i]; - _buffer_size++; - flushbuffer(); - } - } -*/} - - // Reset Serial Setting (baud rate) - bool ESP3DSerialService::reset() { - esp3d_log("Reset serial"); - bool res = false; - switch (_id) { - case MAIN_SERIAL: - return ESP3DSettings::writeUint32( - ESP_BAUD_RATE, - ESP3DSettings::getDefaultIntegerSetting(ESP_BAUD_RATE)); +// Reset Serial Setting (baud rate) +bool ESP3DSerialService::reset() { + esp3d_log("Reset serial"); + bool res = false; + switch (_id) { + case MAIN_SERIAL: + return ESP3DSettings::writeUint32( + ESP_BAUD_RATE, + ESP3DSettings::getDefaultIntegerSetting(ESP_BAUD_RATE)); #if defined(ESP_SERIAL_BRIDGE_OUTPUT) - case BRIDGE_SERIAL: - res = ESP3DSettings::writeByte( - ESP_SERIAL_BRIDGE_ON, - ESP3DSettings::getDefaultByteSetting(ESP_SERIAL_BRIDGE_ON)); - return res && ESP3DSettings::writeUint32( - ESP_SERIAL_BRIDGE_BAUD, - ESP3DSettings::getDefaultIntegerSetting( - ESP_SERIAL_BRIDGE_BAUD)); + case BRIDGE_SERIAL: + res = ESP3DSettings::writeByte( + ESP_SERIAL_BRIDGE_ON, + ESP3DSettings::getDefaultByteSetting(ESP_SERIAL_BRIDGE_ON)); + return res && + ESP3DSettings::writeUint32(ESP_SERIAL_BRIDGE_BAUD, + ESP3DSettings::getDefaultIntegerSetting( + ESP_SERIAL_BRIDGE_BAUD)); #endif // ESP_SERIAL_BRIDGE_OUTPUT - default: - return res; - } - } - - void ESP3DSerialService::updateBaudRate(uint32_t br) { - if (br != _baudRate) { - Serials[_serialIndex]->flush(); - Serials[_serialIndex]->updateBaudRate(br); - _baudRate = br; - } - } - - // Get current baud rate - uint32_t ESP3DSerialService::baudRate() { - - return _baudRate; - } - - size_t ESP3DSerialService::writeBytes(const uint8_t *buffer, size_t size) { - if (!_started) { - return 0; - } - if ((uint)Serials[_serialIndex]->availableForWrite() >= size) { - return Serials[_serialIndex]->write(buffer, size); - } else { - size_t sizetosend = size; - size_t sizesent = 0; - uint8_t *buffertmp = (uint8_t *)buffer; - uint32_t starttime = millis(); - // loop until all is sent or timeout - while (sizetosend > 0 && ((millis() - starttime) < 100)) { - size_t available = Serials[_serialIndex]->availableForWrite(); - if (available > 0) { - // in case less is sent - available = Serials[_serialIndex]->write( - &buffertmp[sizesent], - (available >= sizetosend) ? sizetosend : available); - sizetosend -= available; - sizesent += available; - starttime = millis(); - } else { - ESP3DHal::wait(5); - } - } - return sizesent; - } - } - - size_t ESP3DSerialService::readBytes(uint8_t *sbuf, size_t len) { - if (!_started) { - return -1; - } - return Serials[_serialIndex]->readBytes(sbuf, len); - } - - void ESP3DSerialService::flush() { - if (!_started) { - return; - } - Serials[_serialIndex]->flush(); - } - - void ESP3DSerialService::swap() { - // Nothing to do - } + default: + return res; + } +} - bool ESP3DSerialService::dispatch(ESP3DMessage *message) { - bool done = false; - // Only is serial service is started - if (_started) { - // Only if message is not null - if (message) { - // if message is not null - if (message->data && message->size != 0) { - if (writeBytes(message->data, message->size) == message->size) { - flush(); - // Delete message now - esp3d_message_manager.deleteMsg(message); - done = true; - } else { - esp3d_log_e("Error while sending data"); - } - } else { - esp3d_log_e("Error null data"); - } - } else { - esp3d_log_e("Error null message"); - } - } - return done; - } #endif // COMMUNICATION_PROTOCOL == RAW_SERIAL || // defined(ESP_SERIAL_BRIDGE_OUTPUT) diff --git a/esp3d/src/modules/serial/serial_service_esp8266.cpp b/esp3d/src/modules/serial/serial_service_esp8266.cpp index 98eb2467..26ffeb24 100644 --- a/esp3d/src/modules/serial/serial_service_esp8266.cpp +++ b/esp3d/src/modules/serial/serial_service_esp8266.cpp @@ -32,17 +32,10 @@ #define MAX_SERIAL 2 HardwareSerial *Serials[MAX_SERIAL] = {&Serial, &Serial1}; -// Serial Parameters -#define ESP_SERIAL_PARAM SERIAL_8N1 - -ESP3DSerialService esp3d_serial_service = ESP3DSerialService(MAIN_SERIAL); +#define TIMEOUT_SERIAL_FLUSH 1500 -const uint32_t SupportedBaudList[] = {9600, 19200, 38400, 57600, 74880, - 115200, 230400, 250000, 500000, 921600, - 1000000, 1958400, 2000000}; -const size_t SupportedBaudListSize = sizeof(SupportedBaudList) / sizeof(uint32_t); +// Serial Parameters -#define TIMEOUT_SERIAL_FLUSH 1500 // Constructor ESP3DSerialService::ESP3DSerialService(uint8_t id) { _buffer_size = 0; @@ -59,33 +52,6 @@ ESP3DSerialService::ESP3DSerialService(uint8_t id) { _origin = ESP3DClientType::serial; } -// Destructor -ESP3DSerialService::~ESP3DSerialService() { end(); } - -// extra parameters that do not need a begin -void ESP3DSerialService::setParameters() { -#if defined(AUTHENTICATION_FEATURE) - _needauthentication = - (ESP3DSettings::readByte(ESP_SECURE_SERIAL) == 0) ? false : true; -#else - _needauthentication = false; -#endif // AUTHENTICATION_FEATURE -} - -void ESP3DSerialService::initAuthentication() { -#if defined(AUTHENTICATION_FEATURE) - _auth = ESP3DAuthenticationLevel::guest; -#else - _auth = ESP3DAuthenticationLevel::admin; -#endif // AUTHENTICATION_FEATURE -} -ESP3DAuthenticationLevel ESP3DSerialService::getAuthentication() { - if (_needauthentication) { - return _auth; - } - return ESP3DAuthenticationLevel::admin; -} - // Setup Serial bool ESP3DSerialService::begin(uint8_t serialIndex) { _serialIndex = serialIndex - 1; @@ -133,12 +99,21 @@ bool ESP3DSerialService::end() { return true; } -// return the array of uint32_t and array size -const uint32_t *ESP3DSerialService::get_baudratelist(uint8_t *count) { - if (count) { - *count = sizeof(SupportedBaudList) / sizeof(uint32_t); +void ESP3DSerialService::flushData(const uint8_t *data, size_t size, ESP3DMessageType type) { + ESP3DMessage *message = esp3d_message_manager.newMsg( + _origin, + _id == MAIN_SERIAL ? ESP3DClientType::all_clients + : esp3d_commands.getOutputClient(), + data, size, getAuthentication()); + + if (message) { + message->type = type; + esp3d_log("Process Message"); + esp3d_commands.process(message); + } else { + esp3d_log_e("Cannot create message"); } - return SupportedBaudList; + _lastflush = millis(); } // Function which could be called in other loop @@ -165,33 +140,10 @@ void ESP3DSerialService::handle() { // we cannot left data in buffer too long // in case some commands "forget" to add \n if (((millis() - _lastflush) > TIMEOUT_SERIAL_FLUSH) && (_buffer_size > 0)) { - flushbuffer(); + flushBuffer(); } } - -void ESP3DSerialService::flushbuffer() { - _buffer[_buffer_size] = 0x0; - - // dispatch command - if (_started) { - ESP3DMessage *message = esp3d_message_manager.newMsg( - _origin, - _id == MAIN_SERIAL ? ESP3DClientType::all_clients - : esp3d_commands.getOutputClient(), - (uint8_t *)_buffer, _buffer_size, getAuthentication()); - if (message) { - // process command - message->type = ESP3DMessageType::unique; - esp3d_commands.process(message); - } else { - esp3d_log_e("Cannot create message"); - } - } - _lastflush = millis(); - _buffer_size = 0; -} - // push collected data to buffer and proceed accordingly void ESP3DSerialService::push2buffer(uint8_t *sbuf, size_t len) { if (!_started) { @@ -250,7 +202,7 @@ void ESP3DSerialService::push2buffer(uint8_t *sbuf, size_t len) { if (_buffer_size == datalen) { esp3d_log("Flushing buffer"); if (isCommandFrame) { - flushbuffer(); + flushBuffer(); } else { MKSService::handleFrame(type, (const uint8_t *)_buffer, _buffer_size); @@ -294,31 +246,15 @@ void ESP3DSerialService::push2buffer(uint8_t *sbuf, size_t len) { #else for (size_t i = 0; i < len; i++) { _lastflush = millis(); - // command is defined - if (char(sbuf[i]) == '\n') { - if (_buffer_size < ESP3D_SERIAL_BUFFER_SIZE) { - _buffer[_buffer_size] = sbuf[i]; - _buffer_size++; - } - flushbuffer(); - } else if (esp3d_string::isPrintableChar(char(sbuf[i]))) { - if (_buffer_size < ESP3D_SERIAL_BUFFER_SIZE) { - _buffer[_buffer_size] = sbuf[i]; - _buffer_size++; - } else { - flushbuffer(); - _buffer[_buffer_size] = sbuf[i]; - _buffer_size++; - } - } else { // it is not printable char - // clean buffer first - if (_buffer_size > 0) { - flushbuffer(); - } - // process char + if (esp3d_string::isRealTimeCommand(sbuf[i])) { + flushChar(sbuf[i]); + } else { _buffer[_buffer_size] = sbuf[i]; _buffer_size++; - flushbuffer(); + if (_buffer_size > ESP3D_SERIAL_BUFFER_SIZE || + _buffer[_buffer_size - 1] == '\n') { + flushBuffer(); + } } } #endif @@ -331,94 +267,12 @@ bool ESP3DSerialService::reset() { ESP_BAUD_RATE, ESP3DSettings::getDefaultIntegerSetting(ESP_BAUD_RATE)); } -void ESP3DSerialService::updateBaudRate(uint32_t br) { - if (br != baudRate()) { - Serials[_serialIndex]->flush(); - Serials[_serialIndex]->updateBaudRate(br); - } -} - -// Get current baud rate -uint32_t ESP3DSerialService::baudRate() { - return Serials[_serialIndex]->baudRate(); -} - -size_t ESP3DSerialService::writeBytes(const uint8_t *buffer, size_t size) { - if (!_started) { - return 0; - } - if ((uint)Serials[_serialIndex]->availableForWrite() >= size) { - return Serials[_serialIndex]->write(buffer, size); - } else { - size_t sizetosend = size; - size_t sizesent = 0; - uint8_t *buffertmp = (uint8_t *)buffer; - uint32_t starttime = millis(); - // loop until all is sent or timeout - while (sizetosend > 0 && ((millis() - starttime) < 100)) { - size_t available = Serials[_serialIndex]->availableForWrite(); - if (available > 0) { - // in case less is sent - available = Serials[_serialIndex]->write( - &buffertmp[sizesent], - (available >= sizetosend) ? sizetosend : available); - sizetosend -= available; - sizesent += available; - starttime = millis(); - } else { - ESP3DHal::wait(5); - } - } - return sizesent; - } -} - -size_t ESP3DSerialService::readBytes(uint8_t *sbuf, size_t len) { - if (!_started) { - return -1; - } - return Serials[_serialIndex]->readBytes(sbuf, len); -} - -void ESP3DSerialService::flush() { - if (!_started) { - return; - } - Serials[_serialIndex]->flush(); -} - void ESP3DSerialService::swap() { #ifdef ARDUINO_ARCH_ESP8266 Serials[_serialIndex]->swap(); #endif // ARDUINO_ARCH_ESP8266 } -bool ESP3DSerialService::dispatch(ESP3DMessage *message) { - bool done = false; - // Only is serial service is started - if (_started) { - // Only if message is not null - if (message) { - // if message is not null - if (message->data && message->size != 0) { - if (writeBytes(message->data, message->size) == message->size) { - flush(); - // Delete message now - esp3d_message_manager.deleteMsg(message); - done = true; - } else { - esp3d_log_e("Error while sending data"); - } - } else { - esp3d_log_e("Error null data"); - } - } else { - esp3d_log_e("Error null message"); - } - } - return done; -} - #endif // COMMUNICATION_PROTOCOL == MKS_SERIAL || COMMUNICATION_PROTOCOL == // RAW_SERIAL #endif // ARDUINO_ARCH_ESP8266 \ No newline at end of file diff --git a/tools/fw_simulator/fw_simulator.py b/tools/fw_simulator/fw_simulator.py index a8477ffd..c388ca4c 100644 --- a/tools/fw_simulator/fw_simulator.py +++ b/tools/fw_simulator/fw_simulator.py @@ -5,12 +5,30 @@ import esp3d_common as common import marlin import grbl +import grblhal import repetier import smoothieware +def isRealTimeCommand(c: int) -> bool: + # Convertit en entier si ce n'est pas déjà le cas + if isinstance(c, bytes): + c = c[0] + elif isinstance(c, str): + c = ord(c) + + # Standard characters + if c in [ord('?'), ord('!'), ord('~'), 0x18]: # 0x18 is ^X + return True + + # Range >= 0x80 et <= 0xA4 + if 0x80 <= c <= 0xA4: + return True + + return False + def main(): if len(sys.argv) < 2: - print("Please use one of the follwowing FW: marlin, repetier, smoothieware or grbl.") + print("Please use one of the follwowing FW: marlin, repetier, smoothieware, grbl or grblhal.") return fw_name = sys.argv[1].lower() @@ -23,41 +41,65 @@ def main(): fw = smoothieware elif fw_name == "grbl": fw = grbl + elif fw_name == "grblhal": + fw = grblhal else: print("Firmware not supported : {}".format(fw_name)) return ports = serial.tools.list_ports.comports() - portTFT = "" + portBoard = "" print(common.bcolors.COL_GREEN+"Serial ports detected: "+common.bcolors.END_COL) for port, desc, hwid in sorted(ports): print(common.bcolors.COL_GREEN+" - {}: {} ".format(port, desc)+common.bcolors.END_COL) desc.capitalize() if (desc.find("SERIAL") != -1 or desc.find("UART") != -1): - portTFT = port + portBoard = port print(common.bcolors.COL_GREEN + - "Found " + portTFT + " for ESP3D"+common.bcolors.END_COL) + "Found " + portBoard + " for ESP3D"+common.bcolors.END_COL) break print(common.bcolors.COL_GREEN+"Open port " + str(port)+common.bcolors.END_COL) - if (portTFT == ""): + if (portBoard == ""): print(common.bcolors.COL_RED+"No serial port found"+common.bcolors.END_COL) exit(0) - ser = serial.Serial(portTFT, 1000000) + ser = serial.Serial(portBoard, 115200, timeout=1) print(common.bcolors.COL_GREEN+"Now Simulating: " + fw_name + common.bcolors.END_COL) starttime = common.current_milli_time() # loop forever, just unplug the port to stop the program or do ctrl-c + buffer = bytearray() while True: try: if ser.in_waiting: - line = ser.readline().decode('utf-8').strip() - print(common.bcolors.COL_BLUE+line+common.bcolors.END_COL) - #ignore log lines from TFT - if not line.startswith("["): - response = fw.processLine(line, ser) - if (response != ""): + # Lire un caractère + char = ser.read(1) + if not char: # Timeout + continue + + # Vérifier si c'est une commande temps réel + if isRealTimeCommand(char[0]) and (fw_name == "grbl" or fw_name == "grblhal"): + # Traiter immédiatement la commande temps réel + cmd = char.decode('utf-8', errors='replace') + print(common.bcolors.COL_BLUE + f"RealTime command: {cmd}" + common.bcolors.END_COL) + response = fw.processLine(cmd, ser) + if response: common.send_echo(ser, response) + else: + # Ajouter au buffer + buffer.extend(char) + # Si on trouve une fin de ligne, traiter la ligne + if char == b'\n': + line = buffer.decode('utf-8').strip() + print(common.bcolors.COL_BLUE + line + common.bcolors.END_COL) + if not line.startswith("["): + response = fw.processLine(line, ser) + if response: + common.send_echo(ser, response) + buffer.clear() + except KeyboardInterrupt: - print(common.bcolors.COL_GREEN+"End of program"+common.bcolors.END_COL) - exit(0) + break + except Exception as e: + print(f"Error: {e}") + buffer.clear() # call main function diff --git a/tools/fw_simulator/grblhal.py b/tools/fw_simulator/grblhal.py new file mode 100644 index 00000000..211eddff --- /dev/null +++ b/tools/fw_simulator/grblhal.py @@ -0,0 +1,231 @@ +#!/usr/bin/python +# Marlin GCODE parser / responder + +import time +import re +import random +import esp3d_common as common +positions = { + "X": 0.0, + "Y": 0.0, + "Z": 0.0, + "A": 0.0, + "B": 0.0, + "C": 0.0 +} + +modes = { + "absolute": True +} + +report_counter = 0 + + +def wait(durationms, ser): + nowtime = common.current_milli_time() + while (common.current_milli_time() < nowtime + durationms): + if ser.in_waiting: + line = ser.readline().decode('utf-8').strip() + print(common.bcolors.COL_PURPLE+line+common.bcolors.END_COL) + + +def ok(line): + if (not line.startswith("N")): + return "ok (" + line + ")" + N = re.findall(r'N\d*', line) + if (len(N) > 0): + return "ok " + N[0][1:] + + +# build the response for the busy response, +# simulating the delay of the busy response +def send_busy(ser, nb): + v = nb + while (v > 0): + # FIXME: the message is not this one on grbl + # common.send_echo(ser, "echo:busy: processing") + wait(1000, ser) + v = v - 1 + +# G0/G1 response + + +def G0_G1_response(cmd, line, ser): + global positions + X_val = "" + Y_val = "" + Z_val = "" + A_val = "" + B_val = "" + C_val = "" + # extract X + X = re.findall(r'X[+]*[-]*\d+[\.]*\d*', cmd) + if (len(X) > 0): + X_val = X[0][1:] + # extract Y + Y = re.findall(r'Y[+]*[-]*\d+[\.]*\d*', cmd) + if (len(Y) > 0): + Y_val = Y[0][1:] + # extract Z + Z = re.findall(r'Z[+]*[-]*\d+[\.]*\d*', cmd) + if (len(Z) > 0): + Z_val = Z[0][1:] + # extract A + A = re.findall(r'A[+]*[-]*\d+[\.]*\d*', cmd) + if (len(A) > 0): + A_val = A[0][1:] + # extract B + B = re.findall(r'B[+]*[-]*\d+[\.]*\d*', cmd) + if (len(B) > 0): + B_val = B[0][1:] + # extract C + C = re.findall(r'C[+]*[-]*\d+[\.]*\d*', cmd) + if (len(C) > 0): + C_val = C[0][1:] + if (modes["absolute"]): + if (X_val != ""): + positions["X"] = float(X_val) + if (Y_val != ""): + positions["Y"] = float(Y_val) + if (Z_val != ""): + positions["Z"] = float(Z_val) + if (A_val!= ""): + positions["A"] = float(A_val) + if (B_val!= ""): + positions["B"] = float(B_val) + if (C_val!= ""): + positions["C"] = float(C_val) + return ok(line) + else: + if (X_val != ""): + positions["X"] += float(X_val) + if (Y_val != ""): + positions["Y"] += float(Y_val) + if (Z_val != ""): + positions["Z"] += float(Z_val) + if (A_val!= ""): + positions["A"] += float(A_val) + if (B_val!= ""): + positions["B"] += float(B_val) + if (C_val!= ""): + positions["C"] += float(C_val) + return ok(line) + +# $H response + +def Home_response(cmd, line, ser): + global positions + send_busy(ser, 3) + if (cmd.find("X") != -1): + positions["X"] = 0.00 + if (cmd.find("Y") != -1): + positions["Y"] = 0.00 + if (cmd.find("Z") != -1): + positions["Z"] = 0.00 + if (cmd.find("A")!= -1): + positions["A"] = 0.00 + if (cmd.find("B")!= -1): + positions["B"] = 0.00 + if (cmd.find("C")!= -1): + positions["C"] = 0.00 + if (cmd == "G28"): + positions["X"] = 0.00 + positions["Y"] = 0.00 + positions["Z"] = 0.00 + positions["A"] = 0.00 + positiones["B"] = 0.00 + positions["C"] = 0.00 + return ok(line) + + +# Absolute mode + + +def G90_response(cmd, line, ser): + global modes + modes["absolute"] = True + return ok(line) + +# Relative mode + + +def G91_response(cmd, line, ser): + global modes + modes["absolute"] = False + return ok(line) + +def Jog_response(cmd, line, ser): + if (cmd.find("G91")!= -1): + G91_response(cmd, line, ser) + elif (cmd.find("G90")!= -1): + G90_response(cmd, line, ser) + cmd = cmd.replace("G90", "") + cmd = cmd.replace("G91", "") + cmd = cmd.replace("G21", "") + cmd = cmd.strip() + return G0_G1_response(cmd, line, ser) + +# status response +# "\n" +# "\n" +# "\n" +def status_response(cmd, line, ser): + global positions + global report_counter + wpco = "" + ov = "" + fs = "|FS:0,0" + astate = "" + pn = "" + status = "Idle" + report_counter += 1 + if report_counter == 11: + report_counter = 1 + if report_counter == 1: + wpco = "|WCO:0.000,0.000,0.000,1.000,1.000,1.000" + if report_counter == 2: + #FIXME: use variable to report the override values + ov = "|Ov:100,100,100" + pn = "|Pn:XYZ" + if report_counter >= 3: + astate = "|A:S" + pn = "|Pn:P" + + position = "|MPos:" + "{:.3f}".format(positions["X"]) + "," + "{:.3f}".format( + positions["Y"]) + "," + "{:.3f}".format(positions["Z"]) + "," + "{:.3f}".format(positions["A"]) + "," + "{:.3f}".format(positions["B"]) + "," + "{:.3f}".format(positions["C"]) + return "<" + status + position + fs + wpco + ov + astate + pn + ">\n" + + +# List of supported methods +methods = [ + {"str": "G0", "fn": G0_G1_response}, + {"str": "G1", "fn": G0_G1_response}, + {"str": "$H", "fn": Home_response}, + {"str": "$J=", "fn": Jog_response}, + {"str": "G90", "fn": G90_response}, + {"str": "G91", "fn": G91_response}, + {"str": "?", "fn": status_response}, +] + + +# Process a line of GCODE +def processLine(line, ser): + time.sleep(0.01) + cmd = line + if (line.startswith("N")): + p = line.find(' ') + cmd = line[p+1:] + p = cmd.rfind('*') + cmd = cmd[:p] + global methods + for method in methods: + if cmd.startswith(method["str"]): + return method["fn"](cmd, line, ser) + if line.startswith("M") or line.startswith("G") or line.startswith("N") or line.startswith("$"): + return ok(line) + if line.find("[esp") != -1 or line.find("[0;") != -1 or line.find("[1;") != -1: + return "" + if line.startswith("ESP-ROM") or line.startswith("Build:") or line.startswith("SPIWP:") or line.startswith("mode:")or line.startswith("load:") or line.startswith("entry "): + return "" + #FIXME: this is not grbl response if the command is not recognized + return "echo:Unknown command: \"" + line + "\"\nok" diff --git a/tools/serial_test/serial_test.py b/tools/serial_test/serial_test.py new file mode 100644 index 00000000..51f9e169 --- /dev/null +++ b/tools/serial_test/serial_test.py @@ -0,0 +1,33 @@ +import serial +import time + +# Configuration du port série +ser = serial.Serial( + port='COM4', # Port série Windows + baudrate=115200, # Vitesse en bauds + timeout=1 # Timeout en secondes +) + +def format_char(c): + # Convertit un caractère en sa représentation lisible + if c == b'\r': + return '\\r' + elif c == b'\n': + return '\\n' + else: + return f"{c.decode('ascii', errors='replace')}({ord(c)})" + +try: + print("Lecture du port série COM4. Ctrl+C pour arrêter.") + while True: + if ser.in_waiting > 0: + # Lire un caractère à la fois + char = ser.read(1) + print(format_char(char), end=' ', flush=True) + time.sleep(0.01) # Petit délai pour ne pas surcharger le CPU + +except KeyboardInterrupt: + print("\nArrêt du programme") +finally: + ser.close() + print("Port série fermé") \ No newline at end of file