diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h
index 42f8af2c6e797abc90610c242e401ba462661196..97ceb2abfcb3d132fddea3a88c877a296a47f074 100644
--- a/Marlin/Marlin.h
+++ b/Marlin/Marlin.h
@@ -223,8 +223,8 @@ extern bool Running;
inline bool IsRunning() { return Running; }
inline bool IsStopped() { return !Running; }
-bool enqueuecommand(const char* cmd); //put a single ASCII command at the end of the current buffer or return false when it is full
-void enqueuecommands_P(const char* cmd); //put one or many ASCII commands at the end of the current buffer, read from flash
+bool enqueue_and_echo_command(const char* cmd, bool say_ok=false); //put a single ASCII command at the end of the current buffer or return false when it is full
+void enqueue_and_echo_commands_P(const char* cmd); //put one or many ASCII commands at the end of the current buffer, read from flash
void prepare_arc_move(char isclockwise);
void clamp_to_software_endstops(float target[3]);
diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp
index 7fe9786e08791323666931d66c34092630ddaa42..031da1f36c6f63958df6e6ba6c6a62e869c029c7 100644
--- a/Marlin/Marlin_main.cpp
+++ b/Marlin/Marlin_main.cpp
@@ -276,9 +276,7 @@ const char echomagic[] PROGMEM = "echo:";
const char axis_codes[NUM_AXIS] = {'X', 'Y', 'Z', 'E'};
static bool relative_mode = false; //Determines Absolute or Relative Coordinates
-static char serial_char;
static int serial_count = 0;
-static boolean comment_mode = false;
static char* seen_pointer; ///< A pointer to find chars in the command string (X, Y, Z, E, etc.)
const char* queued_commands_P = NULL; /* pointer to the current line in the active sequence of commands, or NULL when none */
const int sensitive_pins[] = SENSITIVE_PINS; ///< Sensitive pin list for M42
@@ -409,9 +407,7 @@ static uint8_t target_extruder;
static bool filrunoutEnqueued = false;
#endif
-#if ENABLED(SDSUPPORT)
- static bool fromsd[BUFSIZE];
-#endif
+static bool send_ok[BUFSIZE];
#if HAS_SERVOS
Servo servo[NUM_SERVOS];
@@ -483,7 +479,7 @@ static bool drain_queued_commands_P() {
char c;
while ((c = cmd[i]) && c != '\n') i++; // find the end of this gcode command
cmd[i] = '\0';
- if (enqueuecommand(cmd)) { // buffer was not full (else we will retry later)
+ if (enqueue_and_echo_command(cmd)) { // buffer was not full (else we will retry later)
if (c)
queued_commands_P += i + 1; // move to next command
else
@@ -497,32 +493,45 @@ static bool drain_queued_commands_P() {
* Aborts the current queue, if any.
* Note: drain_queued_commands_P() must be called repeatedly to drain the commands afterwards
*/
-void enqueuecommands_P(const char* pgcode) {
+void enqueue_and_echo_commands_P(const char* pgcode) {
queued_commands_P = pgcode;
drain_queued_commands_P(); // first command executed asap (when possible)
}
/**
- * Copy a command directly into the main command buffer, from RAM.
- *
- * This is done in a non-safe way and needs a rework someday.
- * Returns false if it doesn't add any command
+ * Once a new command is in the ring buffer, call this to commit it
*/
-bool enqueuecommand(const char* cmd) {
- if (*cmd == ';' || commands_in_queue >= BUFSIZE) return false;
-
- // This is dangerous if a mixing of serial and this happens
- char* command = command_queue[cmd_queue_index_w];
- strcpy(command, cmd);
- SERIAL_ECHO_START;
- SERIAL_ECHOPGM(MSG_Enqueueing);
- SERIAL_ECHO(command);
- SERIAL_ECHOLNPGM("\"");
+inline void _commit_command(bool say_ok) {
+ send_ok[cmd_queue_index_w] = say_ok;
cmd_queue_index_w = (cmd_queue_index_w + 1) % BUFSIZE;
commands_in_queue++;
+}
+
+/**
+ * Copy a command directly into the main command buffer, from RAM.
+ * Returns true if successfully adds the command
+ */
+inline bool _enqueuecommand(const char* cmd, bool say_ok=false) {
+ if (*cmd == ';' || commands_in_queue >= BUFSIZE) return false;
+ strcpy(command_queue[cmd_queue_index_w], cmd);
+ _commit_command(say_ok);
return true;
}
+/**
+ * Enqueue with Serial Echo
+ */
+bool enqueue_and_echo_command(const char* cmd, bool say_ok/*=false*/) {
+ if (_enqueuecommand(cmd, say_ok)) {
+ SERIAL_ECHO_START;
+ SERIAL_ECHOPGM(MSG_Enqueueing);
+ SERIAL_ECHO(cmd);
+ SERIAL_ECHOLNPGM("\"");
+ return true;
+ }
+ return false;
+}
+
void setup_killpin() {
#if HAS_KILL
SET_INPUT(KILL_PIN);
@@ -679,9 +688,8 @@ void setup() {
SERIAL_ECHOPGM(MSG_PLANNER_BUFFER_BYTES);
SERIAL_ECHOLN((int)sizeof(block_t)*BLOCK_BUFFER_SIZE);
- #if ENABLED(SDSUPPORT)
- for (int8_t i = 0; i < BUFSIZE; i++) fromsd[i] = false;
- #endif
+ // Send "ok" after commands by default
+ for (int8_t i = 0; i < BUFSIZE; i++) send_ok[i] = true;
// loads data from EEPROM if available else uses defaults (and resets step acceleration rate)
Config_RetrieveSettings();
@@ -740,7 +748,7 @@ void setup() {
* - Call LCD update
*/
void loop() {
- if (commands_in_queue < BUFSIZE - 1) get_command();
+ if (commands_in_queue < BUFSIZE) get_command();
#if ENABLED(SDSUPPORT)
card.checkautostart(false);
@@ -800,9 +808,12 @@ void gcode_line_error(const char* err, bool doFlush = true) {
*/
void get_command() {
+ static char serial_line_buffer[MAX_CMD_SIZE];
+ static boolean serial_comment_mode = false;
+
if (drain_queued_commands_P()) return; // priority is given to non-serial commands
- #if ENABLED(NO_TIMEOUTS)
+ #if defined(NO_TIMEOUTS) && NO_TIMEOUTS > 0
static millis_t last_command_time = 0;
millis_t ms = millis();
@@ -817,29 +828,21 @@ void get_command() {
//
while (commands_in_queue < BUFSIZE && MYSERIAL.available() > 0) {
- #if ENABLED(NO_TIMEOUTS)
- last_command_time = ms;
- #endif
-
- serial_char = MYSERIAL.read();
+ char serial_char = MYSERIAL.read();
//
- // If the character ends the line, or the line is full...
+ // If the character ends the line
//
- if (serial_char == '\n' || serial_char == '\r' || serial_count >= MAX_CMD_SIZE - 1) {
+ if (serial_char == '\n' || serial_char == '\r') {
- // end of line == end of comment
- comment_mode = false;
+ serial_comment_mode = false; // end of line == end of comment
if (!serial_count) return; // empty lines just exit
- char* command = command_queue[cmd_queue_index_w];
- command[serial_count] = 0; // terminate string
+ serial_line_buffer[serial_count] = 0; // terminate string
+ serial_count = 0; //reset buffer
- // this item in the queue is not from sd
- #if ENABLED(SDSUPPORT)
- fromsd[cmd_queue_index_w] = false;
- #endif
+ char* command = serial_line_buffer;
while (*command == ' ') command++; // skip any leading spaces
char* npos = (*command == 'N') ? command : NULL; // Require the N parameter to start the line
@@ -904,44 +907,56 @@ void get_command() {
// If command was e-stop process now
if (strcmp(command, "M112") == 0) kill(PSTR(MSG_KILLED));
- cmd_queue_index_w = (cmd_queue_index_w + 1) % BUFSIZE;
- commands_in_queue += 1;
+ #if defined(NO_TIMEOUTS) && NO_TIMEOUTS > 0
+ last_command_time = ms;
+ #endif
- serial_count = 0; //clear buffer
+ // Add the command to the queue
+ _enqueuecommand(serial_line_buffer, true);
+ }
+ else if (serial_count >= MAX_CMD_SIZE - 1) {
+ // Keep fetching, but ignore normal characters beyond the max length
+ // The command will be injected when EOL is reached
}
else if (serial_char == '\\') { // Handle escapes
- if (MYSERIAL.available() > 0 && commands_in_queue < BUFSIZE) {
+ if (MYSERIAL.available() > 0) {
// if we have one more character, copy it over
serial_char = MYSERIAL.read();
- command_queue[cmd_queue_index_w][serial_count++] = serial_char;
+ serial_line_buffer[serial_count++] = serial_char;
}
// otherwise do nothing
}
- else { // its not a newline, carriage return or escape char
- if (serial_char == ';') comment_mode = true;
- if (!comment_mode) command_queue[cmd_queue_index_w][serial_count++] = serial_char;
+ else { // it's not a newline, carriage return or escape char
+ if (serial_char == ';') serial_comment_mode = true;
+ if (!serial_comment_mode) serial_line_buffer[serial_count++] = serial_char;
}
- }
+
+ } // queue has space, serial has data
#if ENABLED(SDSUPPORT)
- if (!card.sdprinting || serial_count) return;
+ static bool stop_buffering = false,
+ sd_comment_mode = false;
+
+ if (!card.sdprinting) return;
// '#' stops reading from SD to the buffer prematurely, so procedural macro calls are possible
- // if it occurs, stop_buffering is triggered and the buffer is ran dry.
+ // if it occurs, stop_buffering is triggered and the buffer is run dry.
// this character _can_ occur in serial com, due to checksums. however, no checksums are used in SD printing
- static bool stop_buffering = false;
if (commands_in_queue == 0) stop_buffering = false;
- while (!card.eof() && commands_in_queue < BUFSIZE && !stop_buffering) {
+ uint16_t sd_count = 0;
+ bool card_eof = card.eof();
+ while (commands_in_queue < BUFSIZE && !card_eof && !stop_buffering) {
int16_t n = card.get();
- serial_char = (char)n;
- if (serial_char == '\n' || serial_char == '\r' ||
- ((serial_char == '#' || serial_char == ':') && !comment_mode) ||
- serial_count >= (MAX_CMD_SIZE - 1) || n == -1
+ char sd_char = (char)n;
+ card_eof = card.eof();
+ if (card_eof || n == -1
+ || sd_char == '\n' || sd_char == '\r'
+ || ((sd_char == '#' || sd_char == ':') && !sd_comment_mode)
) {
- if (card.eof()) {
+ if (card_eof) {
SERIAL_PROTOCOLLNPGM(MSG_FILE_PRINTED);
print_job_stop_ms = millis();
char time[30];
@@ -954,24 +969,24 @@ void get_command() {
card.printingHasFinished();
card.checkautostart(true);
}
- if (serial_char == '#') stop_buffering = true;
+ if (sd_char == '#') stop_buffering = true;
- if (!serial_count) {
- comment_mode = false; //for new command
- return; //if empty line
- }
- command_queue[cmd_queue_index_w][serial_count] = 0; //terminate string
- // if (!comment_mode) {
- fromsd[cmd_queue_index_w] = true;
- commands_in_queue += 1;
- cmd_queue_index_w = (cmd_queue_index_w + 1) % BUFSIZE;
- // }
- comment_mode = false; //for new command
- serial_count = 0; //clear buffer
+ sd_comment_mode = false; //for new command
+
+ if (!sd_count) continue; //skip empty lines
+
+ command_queue[cmd_queue_index_w][sd_count] = '\0'; //terminate string
+ sd_count = 0; //clear buffer
+
+ _commit_command(false);
+ }
+ else if (sd_count >= MAX_CMD_SIZE - 1) {
+ // Keep fetching, but ignore normal characters beyond the max length
+ // The command will be injected when EOL is reached
}
else {
- if (serial_char == ';') comment_mode = true;
- if (!comment_mode) command_queue[cmd_queue_index_w][serial_count++] = serial_char;
+ if (sd_char == ';') sd_comment_mode = true;
+ if (!sd_comment_mode) command_queue[cmd_queue_index_w][sd_count++] = sd_char;
}
}
@@ -2654,7 +2669,7 @@ inline void gcode_G28() {
case MeshStart:
mbl.reset();
probe_point = 0;
- enqueuecommands_P(PSTR("G28\nG29 S2"));
+ enqueue_and_echo_commands_P(PSTR("G28\nG29 S2"));
break;
case MeshNext:
@@ -2693,7 +2708,7 @@ inline void gcode_G28() {
SERIAL_PROTOCOLLNPGM("Mesh probing done.");
probe_point = -1;
mbl.active = 1;
- enqueuecommands_P(PSTR("G28"));
+ enqueue_and_echo_commands_P(PSTR("G28"));
}
break;
@@ -3215,7 +3230,7 @@ inline void gcode_G28() {
SERIAL_ECHOLNPGM(Z_PROBE_END_SCRIPT);
}
#endif
- enqueuecommands_P(PSTR(Z_PROBE_END_SCRIPT));
+ enqueue_and_echo_commands_P(PSTR(Z_PROBE_END_SCRIPT));
st_synchronize();
#endif
@@ -3374,7 +3389,7 @@ inline void gcode_M17() {
}
/**
- * M23: Select a file
+ * M23: Open a file
*/
inline void gcode_M23() {
card.openFile(current_command_args, true);
@@ -5244,7 +5259,7 @@ inline void gcode_M428() {
SERIAL_ERRORLNPGM(MSG_ERR_M428_TOO_FAR);
LCD_ALERTMESSAGEPGM("Err: Too far!");
#if HAS_BUZZER
- enqueuecommands_P(PSTR("M300 S40 P200"));
+ enqueue_and_echo_commands_P(PSTR("M300 S40 P200"));
#endif
err = true;
break;
@@ -5258,7 +5273,7 @@ inline void gcode_M428() {
sync_plan_position();
LCD_ALERTMESSAGEPGM("Offset applied.");
#if HAS_BUZZER
- enqueuecommands_P(PSTR("M300 S659 P200\nM300 S698 P200"));
+ enqueue_and_echo_commands_P(PSTR("M300 S659 P200\nM300 S698 P200"));
#endif
}
}
@@ -6304,9 +6319,7 @@ void FlushSerialRequestResend() {
void ok_to_send() {
refresh_cmd_timeout();
- #if ENABLED(SDSUPPORT)
- if (fromsd[cmd_queue_index_r]) return;
- #endif
+ if (!send_ok[cmd_queue_index_r]) return;
SERIAL_PROTOCOLPGM(MSG_OK);
#if ENABLED(ADVANCED_OK)
char* p = command_queue[cmd_queue_index_r];
@@ -6997,7 +7010,7 @@ void manage_inactivity(bool ignore_stepper_queue/*=false*/) {
filrunout();
#endif
- if (commands_in_queue < BUFSIZE - 1) get_command();
+ if (commands_in_queue < BUFSIZE) get_command();
millis_t ms = millis();
@@ -7054,7 +7067,7 @@ void manage_inactivity(bool ignore_stepper_queue/*=false*/) {
const int HOME_DEBOUNCE_DELAY = 2500;
if (!READ(HOME_PIN)) {
if (!homeDebounceCount) {
- enqueuecommands_P(PSTR("G28"));
+ enqueue_and_echo_commands_P(PSTR("G28"));
LCD_MESSAGEPGM(MSG_AUTO_HOME);
}
if (homeDebounceCount < HOME_DEBOUNCE_DELAY)
@@ -7180,7 +7193,7 @@ void kill(const char* lcd_msg) {
void filrunout() {
if (!filrunoutEnqueued) {
filrunoutEnqueued = true;
- enqueuecommands_P(PSTR(FILAMENT_RUNOUT_SCRIPT));
+ enqueue_and_echo_commands_P(PSTR(FILAMENT_RUNOUT_SCRIPT));
st_synchronize();
}
}
diff --git a/Marlin/cardreader.cpp b/Marlin/cardreader.cpp
index dbbbd551eebf24065035039460f32cb912a574c7..e508190c41057e83b223aee1532d36bd5fd2238c 100644
--- a/Marlin/cardreader.cpp
+++ b/Marlin/cardreader.cpp
@@ -243,6 +243,14 @@ void CardReader::release() {
cardOK = false;
}
+void CardReader::openAndPrintFile(const char *name) {
+ char cmd[4 + (FILENAME_LENGTH + 1) * MAX_DIR_DEPTH + 2]; // Room for "M23 ", names with slashes, a null, and one extra
+ sprintf_P(cmd, PSTR("M23 %s"), name);
+ for (char *c = &cmd[4]; *c; c++) *c = tolower(*c);
+ enqueue_and_echo_command(cmd);
+ enqueue_and_echo_commands_P(PSTR("M24"));
+}
+
void CardReader::startFileprint() {
if (cardOK)
sdprinting = true;
@@ -500,10 +508,7 @@ void CardReader::checkautostart(bool force) {
while (root.readDir(p, NULL) > 0) {
for (int8_t i = 0; i < (int8_t)strlen((char*)p.name); i++) p.name[i] = tolower(p.name[i]);
if (p.name[9] != '~' && strncmp((char*)p.name, autoname, 5) == 0) {
- char cmd[4 + (FILENAME_LENGTH + 1) * (MAX_DIR_DEPTH) + 2];
- sprintf_P(cmd, PSTR("M23 %s"), autoname);
- enqueuecommand(cmd);
- enqueuecommands_P(PSTR("M24"));
+ openAndPrintFile(autoname);
found = true;
}
}
@@ -589,7 +594,7 @@ void CardReader::printingHasFinished() {
sdprinting = false;
if (SD_FINISHED_STEPPERRELEASE) {
//finishAndDisableSteppers();
- enqueuecommands_P(PSTR(SD_FINISHED_RELEASECOMMAND));
+ enqueue_and_echo_commands_P(PSTR(SD_FINISHED_RELEASECOMMAND));
}
autotempShutdown();
}
diff --git a/Marlin/cardreader.h b/Marlin/cardreader.h
index 78f2d289ff543509f6582ac2cf5a53219f2f5dca..db68710d71ab4aebce029f9d012aae4d7fb3038c 100644
--- a/Marlin/cardreader.h
+++ b/Marlin/cardreader.h
@@ -23,6 +23,7 @@ public:
void removeFile(char* name);
void closefile(bool store_location=false);
void release();
+ void openAndPrintFile(const char *name);
void startFileprint();
void pauseSDPrint();
void getStatus();
diff --git a/Marlin/stepper.cpp b/Marlin/stepper.cpp
index 72ee0dfa9e8df32b137cebc0fe1693915d212880..f579112f216a20c3a5f4ca2e78c85f572a0275d0 100644
--- a/Marlin/stepper.cpp
+++ b/Marlin/stepper.cpp
@@ -617,7 +617,7 @@ ISR(TIMER1_COMPA_vect) {
current_block = NULL;
plan_discard_current_block();
#ifdef SD_FINISHED_RELEASECOMMAND
- if ((cleaning_buffer_counter == 1) && (SD_FINISHED_STEPPERRELEASE)) enqueuecommands_P(PSTR(SD_FINISHED_RELEASECOMMAND));
+ if ((cleaning_buffer_counter == 1) && (SD_FINISHED_STEPPERRELEASE)) enqueue_and_echo_commands_P(PSTR(SD_FINISHED_RELEASECOMMAND));
#endif
cleaning_buffer_counter--;
OCR1A = 200;
diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp
index 6f9fce382e059c619514beaf291b389af2ca8158..1e2fbb37b4628a639cc12a7d28b1ac10ac93b1af 100644
--- a/Marlin/ultralcd.cpp
+++ b/Marlin/ultralcd.cpp
@@ -479,7 +479,7 @@ static void lcd_main_menu() {
*/
void lcd_set_home_offsets() {
// M428 Command
- enqueuecommands_P(PSTR("M428"));
+ enqueue_and_echo_commands_P(PSTR("M428"));
lcd_return_to_status();
}
@@ -1504,7 +1504,7 @@ menu_edit_type(unsigned long, long5, ftostr5, 0.01)
lcd_move_y();
}
static void reprapworld_keypad_move_home() {
- enqueuecommands_P((PSTR("G28"))); // move all axis home
+ enqueue_and_echo_commands_P((PSTR("G28"))); // move all axis home
}
#endif // REPRAPWORLD_KEYPAD
@@ -1556,18 +1556,13 @@ void lcd_quick_feedback() {
*/
static void menu_action_back(menuFunc_t func) { lcd_goto_menu(func); }
static void menu_action_submenu(menuFunc_t func) { lcd_save_previous_menu(); lcd_goto_menu(func); }
-static void menu_action_gcode(const char* pgcode) { enqueuecommands_P(pgcode); }
+static void menu_action_gcode(const char* pgcode) { enqueue_and_echo_commands_P(pgcode); }
static void menu_action_function(menuFunc_t func) { (*func)(); }
#if ENABLED(SDSUPPORT)
static void menu_action_sdfile(const char* filename, char* longFilename) {
- char cmd[30];
- char* c;
- sprintf_P(cmd, PSTR("M23 %s"), filename);
- for (c = &cmd[4]; *c; c++) *c = tolower(*c);
- enqueuecommand(cmd);
- enqueuecommands_P(PSTR("M24"));
+ card.openAndPrintFile(filename);
lcd_return_to_status();
}
@@ -2313,7 +2308,7 @@ char* ftostr52(const float& x) {
current_position[Z_AXIS] = MESH_HOME_SEARCH_Z;
line_to_current(Z_AXIS);
mbl.active = 1;
- enqueuecommands_P(PSTR("G28"));
+ enqueue_and_echo_commands_P(PSTR("G28"));
lcd_return_to_status();
}
else {
@@ -2357,7 +2352,7 @@ char* ftostr52(const float& x) {
static void lcd_level_bed() {
axis_known_position[X_AXIS] = axis_known_position[Y_AXIS] = axis_known_position[Z_AXIS] = false;
mbl.reset();
- enqueuecommands_P(PSTR("G28"));
+ enqueue_and_echo_commands_P(PSTR("G28"));
lcdDrawUpdate = 2;
lcd_goto_menu(_lcd_level_bed_homing);
}