mirror of
https://git.mirrors.martin98.com/https://github.com/luc-github/ESP3D.git
synced 2025-08-11 08:19:00 +08:00
Grbl grblHAL better support for realtime commands (#1064)
* Add a realtime command detector * Move `\r` as printable char and not replaced as `\n` * 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 * Implement isRealTimeCommand for BT client * Simplify BT push2buffer code * Implement support for realtimecommand in telnet * Implement isRealTimeCommand on websocket RX * Simplify push2RXbuffer for websocket * Implement isRealTimeCommand for USB serial * Bump version
This commit is contained in:
parent
7b99d8a020
commit
fe23f0cb1e
@ -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
|
||||
|
||||
/************************************
|
||||
*
|
||||
|
@ -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
|
||||
|
@ -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';
|
||||
@ -1205,10 +1199,6 @@ void ESP3DCommands::process(ESP3DMessage *msg) {
|
||||
esp3d_log("Execute internal command %d", cmdId);
|
||||
execute_internal_command(cmdId, espcmdpos, msg);
|
||||
} else {
|
||||
/*esp3d_log("Dispatch command, len %d, from %d(%s) to %d(%s)", msg->size,
|
||||
static_cast<uint8_t>(msg->origin), GETCLIENTSTR(msg->origin),
|
||||
static_cast<uint8_t>(msg->target), GETCLIENTSTR(msg->target));*/
|
||||
|
||||
// Work around to avoid to dispatch single \n or \r to everyone as it is
|
||||
// part of previous ESP3D command
|
||||
if (msg->size == 1 &&
|
||||
@ -1237,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 = "";
|
||||
@ -1254,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);
|
||||
@ -1263,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);
|
||||
@ -1472,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();
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "../include/esp3d_config.h"
|
||||
#include "esp3d_settings.h"
|
||||
|
||||
#if defined(WIFI_FEATURE) || defined(ETH_FEATURE)
|
||||
#include "../modules/network/netconfig.h"
|
||||
@ -174,16 +175,16 @@ const char* esp3d_string::urlEncode(const char* s) {
|
||||
static String encoded;
|
||||
encoded = "";
|
||||
char temp[4];
|
||||
for (int i = 0; i < strlen(s); i++) {
|
||||
temp[0] =s[i];
|
||||
if (temp[0] == 32) { //space
|
||||
for (size_t i = 0; i < strlen(s); i++) {
|
||||
temp[0] = s[i];
|
||||
if (temp[0] == 32) { // space
|
||||
encoded.concat('+');
|
||||
} else if ((temp[0] >= 48 && temp[0] <= 57) /*0-9*/
|
||||
|| (temp[0] >= 65 && temp[0] <= 90) /*A-Z*/
|
||||
|| (temp[0] >= 97 && temp[0] <= 122) /*a-z*/
|
||||
} else if ((temp[0] >= 48 && temp[0] <= 57) /*0-9*/
|
||||
|| (temp[0] >= 65 && temp[0] <= 90) /*A-Z*/
|
||||
|| (temp[0] >= 97 && temp[0] <= 122) /*a-z*/
|
||||
) {
|
||||
encoded.concat(temp[0]);
|
||||
} else { //character needs encoding
|
||||
} else { // character needs encoding
|
||||
snprintf(temp, 4, "%%%02X", temp[0]);
|
||||
encoded.concat(temp);
|
||||
}
|
||||
@ -208,7 +209,7 @@ const char* esp3d_string::formatBytes(uint64_t bytes) {
|
||||
|
||||
bool esp3d_string::isPrintableChar(char ch) {
|
||||
int c = static_cast<int>(ch);
|
||||
if (c == 9 || (c >= 32 && c <= 126) || c >= 128) {
|
||||
if (c == '\t' || c == '\r' || (c >= ' ' && c <= '~') || c >= 128) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -254,7 +255,7 @@ const char* esp3d_string::formatDuration(uint64_t duration) {
|
||||
display = true;
|
||||
}
|
||||
if (hours > 0 || display) {
|
||||
result+= String(hours) + "h ";
|
||||
result += String(hours) + "h ";
|
||||
display = true;
|
||||
}
|
||||
if (minutes > 0 || display) {
|
||||
@ -264,4 +265,21 @@ const char* esp3d_string::formatDuration(uint64_t duration) {
|
||||
result += String(seconds) + "s";
|
||||
|
||||
return result.c_str();
|
||||
}
|
||||
|
||||
bool esp3d_string::isRealTimeCommand(char c) {
|
||||
if (ESP3DSettings::GetFirmwareTarget() == GRBL ||
|
||||
ESP3DSettings::GetFirmwareTarget() == GRBLHAL) {
|
||||
// Standard characters
|
||||
if (c == '?' || c == '!' || c == '~' || c == 0x18) { // 0x18 is ^X
|
||||
return true;
|
||||
}
|
||||
|
||||
// Range >= 0x80 et <= 0xA4
|
||||
const unsigned char uc = static_cast<unsigned char>(c);
|
||||
if (uc >= 0x80 && uc <= 0xA4) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
@ -31,6 +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);
|
||||
} // namespace esp3d_string
|
||||
|
||||
#endif //_ESP3D_STRING_H
|
||||
|
@ -22,7 +22,7 @@
|
||||
#define _VERSION_ESP3D_H
|
||||
|
||||
// version and sources location
|
||||
#define FW_VERSION "3.0.0.a244"
|
||||
#define FW_VERSION "3.0.0.a245"
|
||||
#define REPOSITORY "https://github.com/luc-github/ESP3D/tree/3.0"
|
||||
|
||||
#endif //_VERSION_ESP3D_H
|
||||
|
@ -176,7 +176,7 @@ void BTService::handle() {
|
||||
// we cannot left data in buffer too long
|
||||
// in case some commands "forget" to add \n
|
||||
if (((millis() - _lastflush) > TIMEOUT_BT_FLUSH) && (_buffer_size > 0)) {
|
||||
flushbuffer();
|
||||
flushBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,51 +189,48 @@ void BTService::initAuthentication() {
|
||||
}
|
||||
ESP3DAuthenticationLevel BTService::getAuthentication() { return _auth; }
|
||||
|
||||
void BTService::flushbuffer() {
|
||||
_buffer[_buffer_size] = 0x0;
|
||||
// dispatch command
|
||||
ESP3DMessage *msg = esp3d_message_manager.newMsg(
|
||||
ESP3DClientType::bluetooth, esp3d_commands.getOutputClient(), _buffer,
|
||||
_buffer_size, _auth);
|
||||
if (msg) {
|
||||
// process command
|
||||
esp3d_commands.process(msg);
|
||||
void BTService::flushData(const uint8_t *data, size_t size,
|
||||
ESP3DMessageType type) {
|
||||
ESP3DMessage *message = esp3d_message_manager.newMsg(
|
||||
ESP3DClientType::bluetooth, esp3d_commands.getOutputClient(), data,
|
||||
size, _auth);
|
||||
|
||||
if (message) {
|
||||
message->type = type;
|
||||
esp3d_log("Process Message");
|
||||
esp3d_commands.process(message);
|
||||
} else {
|
||||
esp3d_log_e("Cannot create message");
|
||||
}
|
||||
_lastflush = millis();
|
||||
}
|
||||
|
||||
void BTService::flushChar(char c) {
|
||||
flushData((uint8_t *)&c, 1, ESP3DMessageType::realtimecmd);
|
||||
}
|
||||
|
||||
void BTService::flushBuffer() {
|
||||
_buffer[_buffer_size] = 0x0;
|
||||
flushData((uint8_t *)_buffer, _buffer_size, ESP3DMessageType::unique);
|
||||
_buffer_size = 0;
|
||||
}
|
||||
|
||||
// push collected data to buffer and proceed accordingly
|
||||
void BTService::push2buffer(uint8_t *sbuf, size_t len) {
|
||||
if (!_buffer || !_started) {
|
||||
return;
|
||||
}
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
_lastflush = millis();
|
||||
// command is defined
|
||||
if ((char(sbuf[i]) == '\n') || (char(sbuf[i]) == '\r')) {
|
||||
if (_buffer_size < ESP3D_BT_BUFFER_SIZE) {
|
||||
_buffer[_buffer_size] = sbuf[i];
|
||||
_buffer_size++;
|
||||
}
|
||||
flushbuffer();
|
||||
} else if (esp3d_string::isPrintableChar(char(sbuf[i]))) {
|
||||
if (_buffer_size < ESP3D_BT_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_BT_BUFFER_SIZE ||
|
||||
_buffer[_buffer_size - 1] == '\n') {
|
||||
flushBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,9 @@ class BTService {
|
||||
uint8_t _buffer[ESP3D_BT_BUFFER_SIZE + 1]; // keep space of 0x0 terminal
|
||||
size_t _buffer_size;
|
||||
void push2buffer(uint8_t* sbuf, size_t len);
|
||||
void flushbuffer();
|
||||
void flushBuffer();
|
||||
void flushChar(char c);
|
||||
void flushData(const uint8_t* data, size_t size, ESP3DMessageType type);
|
||||
bool _started;
|
||||
};
|
||||
|
||||
|
@ -81,7 +81,7 @@ bool GcodeHost::push(const uint8_t *sbuf, size_t len) {
|
||||
esp3d_log("Push got %d bytes", len);
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
// it is a line process it
|
||||
if (sbuf[i] == '\n' || sbuf[i] == '\r') {
|
||||
if (sbuf[i] == '\n') {
|
||||
flush();
|
||||
} else {
|
||||
// fill buffer until it is full
|
||||
@ -263,7 +263,7 @@ void GcodeHost::readNextCommand() {
|
||||
} else {
|
||||
_processedSize++;
|
||||
_currentPosition++;
|
||||
if (!(((char)c == '\n') || ((char)c == '\r'))) {
|
||||
if (!((char)c == '\n')) {
|
||||
_currentCommand += (char)c;
|
||||
} else {
|
||||
processing = false;
|
||||
@ -290,7 +290,7 @@ void GcodeHost::readNextCommand() {
|
||||
} else {
|
||||
_processedSize++;
|
||||
_currentPosition++;
|
||||
if (!(((char)c == '\n') || ((char)c == '\r'))) {
|
||||
if (!(char)c == '\n' ) {
|
||||
_currentCommand += (char)c;
|
||||
} else {
|
||||
processing = false;
|
||||
|
@ -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,32 +43,42 @@ 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(),
|
||||
(uint8_t *)cmd.c_str(), cmd.length(), auth_level);
|
||||
if (msg) {
|
||||
msg->type = ESP3DMessageType::unique;
|
||||
msg->type = ESP3DMessageType::unique; //ESP3D command is always unique
|
||||
msg->request_id.code = 200;
|
||||
// process command
|
||||
esp3d_commands.process(msg);
|
||||
@ -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")) {
|
||||
|
@ -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) {
|
||||
|
176
esp3d/src/modules/serial/serial_service.cpp
Normal file
176
esp3d/src/modules/serial/serial_service.cpp
Normal file
@ -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)
|
@ -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;
|
||||
|
@ -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,15 +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' ||
|
||||
_buffer[_buffer_size - 1] == '\r') {
|
||||
if (_buffer[_buffer_size - 1] == '\r') {
|
||||
_buffer[_buffer_size - 1] = '\n';
|
||||
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();
|
||||
}
|
||||
flushbuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -229,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
|
||||
@ -258,179 +229,30 @@ void ESP3DSerialService::handle() {
|
||||
}
|
||||
}
|
||||
|
||||
void ESP3DSerialService::flushbuffer() {
|
||||
_buffer[_buffer_size] = 0x0;
|
||||
if (_buffer_size == 1 && _buffer[0] == '\n') {
|
||||
_buffer_size = 0;
|
||||
return;
|
||||
// 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));
|
||||
#endif // ESP_SERIAL_BRIDGE_OUTPUT
|
||||
default:
|
||||
return res;
|
||||
}
|
||||
|
||||
// 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') || (char(sbuf[i]) == '\r')) {
|
||||
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));
|
||||
#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));
|
||||
#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
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -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);
|
||||
|
||||
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
|
||||
|
||||
// Serial Parameters
|
||||
|
||||
// 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,36 +140,13 @@ 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) {
|
||||
if (!_started || !_buffer) {
|
||||
return;
|
||||
}
|
||||
esp3d_log("buffer get %d data ", len);
|
||||
@ -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') || (char(sbuf[i]) == '\r')) {
|
||||
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
|
@ -99,7 +99,7 @@ size_t Serial_2_Socket::write(const uint8_t *buffer, size_t size) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
_TXbuffer[_TXbufferSize] = buffer[i];
|
||||
_TXbufferSize++;
|
||||
if (buffer[i] == (const uint8_t)'\n' || buffer[i] == (const uint8_t)'\r') {
|
||||
if (buffer[i] == (const uint8_t)'\n') {
|
||||
esp3d_log("S2S: %s TXSize: %d", (const char *)_TXbuffer, _TXbufferSize);
|
||||
flush();
|
||||
}
|
||||
|
@ -186,7 +186,7 @@ void Telnet_Server::handle() {
|
||||
// we cannot left data in buffer too long
|
||||
// in case some commands "forget" to add \n
|
||||
if (((millis() - _lastflush) > TIMEOUT_TELNET_FLUSH) && (_buffer_size > 0)) {
|
||||
flushbuffer();
|
||||
flushBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
@ -214,57 +214,48 @@ void Telnet_Server::initAuthentication() {
|
||||
}
|
||||
ESP3DAuthenticationLevel Telnet_Server::getAuthentication() { return _auth; }
|
||||
|
||||
void Telnet_Server::flushbuffer() {
|
||||
if (!_buffer || !_started) {
|
||||
_buffer_size = 0;
|
||||
return;
|
||||
}
|
||||
_buffer[_buffer_size] = 0x0;
|
||||
ESP3DMessage *msg = esp3d_message_manager.newMsg(
|
||||
ESP3DClientType::telnet, esp3d_commands.getOutputClient(), _buffer,
|
||||
_buffer_size, _auth);
|
||||
if (msg) {
|
||||
// process command
|
||||
esp3d_commands.process(msg);
|
||||
|
||||
|
||||
void Telnet_Server::flushData(const uint8_t *data, size_t size, ESP3DMessageType type) {
|
||||
ESP3DMessage *message = esp3d_message_manager.newMsg(
|
||||
ESP3DClientType::telnet, esp3d_commands.getOutputClient(), data,
|
||||
size, _auth);
|
||||
|
||||
if (message) {
|
||||
message->type = type;
|
||||
esp3d_log("Process Message");
|
||||
esp3d_commands.process(message);
|
||||
} else {
|
||||
esp3d_log_e("Cannot create message");
|
||||
}
|
||||
|
||||
_lastflush = millis();
|
||||
}
|
||||
|
||||
|
||||
void Telnet_Server::flushChar(char c) { flushData((uint8_t *)&c, 1, ESP3DMessageType::realtimecmd); }
|
||||
|
||||
void Telnet_Server::flushBuffer() {
|
||||
_buffer[_buffer_size] = 0x0;
|
||||
flushData((uint8_t *)_buffer, _buffer_size, ESP3DMessageType::unique);
|
||||
_buffer_size = 0;
|
||||
}
|
||||
|
||||
|
||||
void Telnet_Server::push2buffer(uint8_t *sbuf, size_t len) {
|
||||
if (!_buffer) {
|
||||
if (!_buffer || !_started) {
|
||||
return;
|
||||
}
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
_lastflush = millis();
|
||||
// command is defined
|
||||
if ((char(sbuf[i]) == '\n') || (char(sbuf[i]) == '\r')) {
|
||||
if (_buffer_size < ESP3D_TELNET_BUFFER_SIZE) {
|
||||
_buffer[_buffer_size] = sbuf[i];
|
||||
_buffer_size++;
|
||||
}
|
||||
flushbuffer();
|
||||
} else if (esp3d_string::isPrintableChar(char(sbuf[i]))) {
|
||||
if (_buffer_size < ESP3D_TELNET_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_TELNET_BUFFER_SIZE ||
|
||||
_buffer[_buffer_size - 1] == '\n') {
|
||||
flushBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -62,7 +62,9 @@ class Telnet_Server {
|
||||
uint8_t* _buffer;
|
||||
size_t _buffer_size;
|
||||
void push2buffer(uint8_t* sbuf, size_t len);
|
||||
void flushbuffer();
|
||||
void flushBuffer();
|
||||
void flushChar(char c);
|
||||
void flushData(const uint8_t* data, size_t size, ESP3DMessageType type);
|
||||
};
|
||||
|
||||
extern Telnet_Server telnet_server;
|
||||
|
@ -174,15 +174,15 @@ void ESP3DUsbSerialService::receiveCb(const uint8_t *data, size_t data_len,
|
||||
}
|
||||
if (xSemaphoreTake(_buffer_mutex, portMAX_DELAY) == pdTRUE) {
|
||||
for (size_t i = 0; i < data_len; i++) {
|
||||
_buffer[_buffer_size] = data[i];
|
||||
_buffer_size++;
|
||||
if (_buffer_size > ESP3D_USB_SERIAL_BUFFER_SIZE ||
|
||||
_buffer[_buffer_size - 1] == '\n' ||
|
||||
_buffer[_buffer_size - 1] == '\r') {
|
||||
if (_buffer[_buffer_size - 1] == '\r') {
|
||||
_buffer[_buffer_size - 1] = '\n';
|
||||
if (esp3d_string::isRealTimeCommand(data[i])) {
|
||||
flushChar(data[i]);
|
||||
} else {
|
||||
_buffer[_buffer_size] = data[i];
|
||||
_buffer_size++;
|
||||
if (_buffer_size > ESP3D_USB_SERIAL_BUFFER_SIZE ||
|
||||
_buffer[_buffer_size - 1] == '\n') {
|
||||
flushBuffer();
|
||||
}
|
||||
flushbuffer();
|
||||
}
|
||||
}
|
||||
xSemaphoreGive(_buffer_mutex);
|
||||
@ -397,26 +397,31 @@ void ESP3DUsbSerialService::handle() {
|
||||
}
|
||||
}
|
||||
|
||||
void ESP3DUsbSerialService::flushbuffer() {
|
||||
_buffer[_buffer_size] = 0x0;
|
||||
if (_buffer_size == 1 && _buffer[0] == '\n') {
|
||||
_buffer_size = 0;
|
||||
void ESP3DUsbSerialService::flushData(const uint8_t *data, size_t size,
|
||||
ESP3DMessageType type) {
|
||||
if (!data || !_started) {
|
||||
return;
|
||||
}
|
||||
|
||||
// dispatch command
|
||||
ESP3DMessage *message = esp3d_message_manager.newMsg(
|
||||
_origin, ESP3DClientType::all_clients, (uint8_t *)_buffer, _buffer_size,
|
||||
getAuthentication());
|
||||
_origin, ESP3DClientType::all_clients, data, size, getAuthentication());
|
||||
if (message) {
|
||||
// process command
|
||||
message->type = ESP3DMessageType::unique;
|
||||
message->type = type;
|
||||
esp3d_log("Message sent to fifo list");
|
||||
_messagesInFIFO.push(message);
|
||||
} else {
|
||||
esp3d_log_e("Cannot create message");
|
||||
}
|
||||
_lastflush = millis();
|
||||
}
|
||||
|
||||
void ESP3DUsbSerialService::flushChar(char c) {
|
||||
flushData((uint8_t *)&c, 1, ESP3DMessageType::realtimecmd);
|
||||
}
|
||||
|
||||
void ESP3DUsbSerialService::flushBuffer() {
|
||||
_buffer[_buffer_size] = 0x0;
|
||||
flushData((uint8_t *)_buffer, _buffer_size, ESP3DMessageType::unique);
|
||||
_buffer_size = 0;
|
||||
}
|
||||
|
||||
|
@ -79,7 +79,9 @@ class ESP3DUsbSerialService final {
|
||||
|
||||
TaskHandle_t _xHandle;
|
||||
ESP3DMessageFIFO _messagesInFIFO;
|
||||
void flushbuffer();
|
||||
void flushBuffer();
|
||||
void flushChar(char c);
|
||||
void flushData(const uint8_t* data, size_t size, ESP3DMessageType type);
|
||||
};
|
||||
|
||||
extern ESP3DUsbSerialService esp3d_usb_serial_service;
|
||||
|
@ -281,36 +281,20 @@ size_t WebSocket_Server::writeBytes(const uint8_t *buffer, size_t size) {
|
||||
}
|
||||
|
||||
void WebSocket_Server::push2RXbuffer(uint8_t *sbuf, size_t len) {
|
||||
if (!_RXbuffer || !_started) {
|
||||
if (!_RXbuffer || !_started || !sbuf) {
|
||||
return;
|
||||
}
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
_lastRXflush = millis();
|
||||
// command is defined
|
||||
if ((char(sbuf[i]) == '\n') || (char(sbuf[i]) == '\r')) {
|
||||
if (_RXbufferSize < RXBUFFERSIZE) {
|
||||
_RXbuffer[_RXbufferSize] = sbuf[i];
|
||||
_RXbufferSize++;
|
||||
}
|
||||
flushRXbuffer();
|
||||
} else if (esp3d_string::isPrintableChar(char(sbuf[i]))) {
|
||||
if (_RXbufferSize < RXBUFFERSIZE) {
|
||||
_RXbuffer[_RXbufferSize] = sbuf[i];
|
||||
_RXbufferSize++;
|
||||
} else {
|
||||
flushRXbuffer();
|
||||
_RXbuffer[_RXbufferSize] = sbuf[i];
|
||||
_RXbufferSize++;
|
||||
}
|
||||
} else { // it is not printable char
|
||||
// clean buffer first
|
||||
if (_RXbufferSize > 0) {
|
||||
flushRXbuffer();
|
||||
}
|
||||
// process char
|
||||
if (esp3d_string::isRealTimeCommand(sbuf[i])) {
|
||||
flushRXChar(sbuf[i]);
|
||||
} else {
|
||||
_RXbuffer[_RXbufferSize] = sbuf[i];
|
||||
_RXbufferSize++;
|
||||
flushRXbuffer();
|
||||
if (_RXbufferSize > RXBUFFERSIZE ||
|
||||
_RXbuffer[_RXbufferSize - 1] == '\n') {
|
||||
flushRXbuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -324,22 +308,33 @@ void WebSocket_Server::initAuthentication() {
|
||||
}
|
||||
ESP3DAuthenticationLevel WebSocket_Server::getAuthentication() { return _auth; }
|
||||
|
||||
void WebSocket_Server::flushRXChar(char c) {
|
||||
flushRXData((uint8_t *)&c, 1, ESP3DMessageType::realtimecmd);
|
||||
}
|
||||
|
||||
void WebSocket_Server::flushRXbuffer() {
|
||||
if (!_RXbuffer || !_started) {
|
||||
_RXbufferSize = 0;
|
||||
_RXbuffer[_RXbufferSize] = 0x0;
|
||||
flushRXData((uint8_t *)_RXbuffer, _RXbufferSize, ESP3DMessageType::unique);
|
||||
_RXbufferSize = 0;
|
||||
}
|
||||
|
||||
void WebSocket_Server::flushRXData(const uint8_t *data, size_t size,
|
||||
ESP3DMessageType type) {
|
||||
if (!data || !_started) {
|
||||
return;
|
||||
}
|
||||
_RXbuffer[_RXbufferSize] = 0x0;
|
||||
ESP3DMessage *msg = esp3d_message_manager.newMsg(
|
||||
_type, esp3d_commands.getOutputClient(), _RXbuffer, _RXbufferSize, _auth);
|
||||
if (msg) {
|
||||
// process command
|
||||
esp3d_commands.process(msg);
|
||||
ESP3DMessage *message = esp3d_message_manager.newMsg(
|
||||
_type, esp3d_commands.getOutputClient(),
|
||||
data, size, _auth);
|
||||
|
||||
if (message) {
|
||||
message->type = type;
|
||||
esp3d_log("Process Message");
|
||||
esp3d_commands.process(message);
|
||||
} else {
|
||||
esp3d_log_e("Cannot create message");
|
||||
}
|
||||
_lastRXflush = millis();
|
||||
_RXbufferSize = 0;
|
||||
}
|
||||
|
||||
void WebSocket_Server::handle() {
|
||||
|
@ -70,6 +70,8 @@ class WebSocket_Server {
|
||||
uint8_t _current_id;
|
||||
void flushTXbuffer();
|
||||
void flushRXbuffer();
|
||||
void flushRXChar(char c);
|
||||
void flushRXData(const uint8_t* data, size_t size, ESP3DMessageType type);
|
||||
uint8_t *_RXbuffer;
|
||||
uint16_t _RXbufferSize;
|
||||
};
|
||||
|
@ -5,12 +5,30 @@ import serial.tools.list_ports
|
||||
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
|
||||
|
231
tools/fw_simulator/grblhal.py
Normal file
231
tools/fw_simulator/grblhal.py
Normal file
@ -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
|
||||
# "<Idle|MPos:0.000,0.000,0.000,1.000,1.000|FS:0,0|WCO:0.000,0.000,0.000,1.000,1.000>\n"
|
||||
# "<Idle|MPos:0.000,0.000,0.000,1.000,1.000|FS:0,0|A:S|Pn:P>\n"
|
||||
# "<Idle|MPos:0.000,0.000,0.000,1.000,1.000|FS:0,0|Ov:100,100,100|Pn:XYZ>\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"
|
33
tools/serial_test/serial_test.py
Normal file
33
tools/serial_test/serial_test.py
Normal file
@ -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é")
|
Loading…
x
Reference in New Issue
Block a user