@ -276,9 +276,7 @@ const char echomagic[] PROGMEM = "echo:";
const char axis_codes [ NUM_AXIS ] = { ' X ' , ' Y ' , ' Z ' , ' E ' } ;
const char axis_codes [ NUM_AXIS ] = { ' X ' , ' Y ' , ' Z ' , ' E ' } ;
static bool relative_mode = false ; //Determines Absolute or Relative Coordinates
static bool relative_mode = false ; //Determines Absolute or Relative Coordinates
static char serial_char ;
static int serial_count = 0 ;
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.)
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 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
const int sensitive_pins [ ] = SENSITIVE_PINS ; ///< Sensitive pin list for M42
@ -409,9 +407,7 @@ static uint8_t target_extruder;
static bool filrunoutEnqueued = false ;
static bool filrunoutEnqueued = false ;
# endif
# endif
# if ENABLED(SDSUPPORT)
static bool send_ok [ BUFSIZE ] ;
static bool fromsd [ BUFSIZE ] ;
# endif
# if HAS_SERVOS
# if HAS_SERVOS
Servo servo [ NUM_SERVOS ] ;
Servo servo [ NUM_SERVOS ] ;
@ -487,29 +483,28 @@ extern "C" {
# endif //!SDSUPPORT
# endif //!SDSUPPORT
/**
/**
* Inject the next command from the command queue , when possible
* Inject the next " immediate " command , when possible .
* Return false only if no command was pending
* Return true if any immediate commands remain to inject .
*/
*/
static bool drain_queued_commands_P ( ) {
static bool drain_queued_commands_P ( ) {
if ( ! queued_commands_P ) return false ;
if ( queued_commands_P ! = NULL ) {
// Get the next gcode to run
// Get the next 30 chars from the sequence of gcodes to run
char cmd [ 30 ] ;
strncpy_P ( cmd , queued_commands_P , sizeof ( cmd ) - 1 ) ;
cmd [ sizeof ( cmd ) - 1 ] = ' \0 ' ;
// Look for the end of line, or the end of sequence
size_t i = 0 ;
size_t i = 0 ;
char c ;
char c ;
while ( ( c = cmd [ i ] ) & & c ! = ' \n ' ) i + + ; // find the end of this gcode command
while ( ( c = queued_commands_P [ i + + ] ) & & c ! = ' \n ' ) { } ;
cmd [ i ] = ' \0 ' ;
if ( i > 1 ) {
if ( enqueuecommand ( cmd ) ) { // buffer was not full (else we will retry later)
char cmd [ i ] ;
strncpy_P ( cmd , queued_commands_P , i - 1 ) ;
cmd [ i - 1 ] = ' \0 ' ;
if ( enqueue_and_echo_command ( cmd ) ) { // buffer was not full (else we will retry later)
if ( c )
if ( c )
queued_commands_P + = i + 1 ; // move to next command
queued_commands_P + = i ; // move to next command
else
else
queued_commands_P = NULL ; // will have no more commands in the sequence
queued_commands_P = NULL ; // no more commands in the sequence
}
}
return true ;
}
}
return ( queued_commands_P ! = NULL ) ; // any more left to add?
}
}
/**
/**
@ -517,30 +512,43 @@ static bool drain_queued_commands_P() {
* Aborts the current queue , if any .
* Aborts the current queue , if any .
* Note : drain_queued_commands_P ( ) must be called repeatedly to drain the commands afterwards
* Note : drain_queued_commands_P ( ) must be called repeatedly to drain the commands afterwards
*/
*/
void enqueue commands_P( const char * pgcode ) {
void enqueue _and_echo_ commands_P( const char * pgcode ) {
queued_commands_P = pgcode ;
queued_commands_P = pgcode ;
drain_queued_commands_P ( ) ; // first command executed asap (when possible)
drain_queued_commands_P ( ) ; // first command executed asap (when possible)
}
}
/**
* Once a new command is in the ring buffer , call this to commit it
*/
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 .
* Copy a command directly into the main command buffer , from RAM .
*
* Returns true if successfully adds the command
* This is done in a non - safe way and needs a rework someday .
* Returns false if it doesn ' t add any command
*/
*/
bool enqueuecommand ( const char * cmd ) {
inline bool _enqueuecommand ( const char * cmd , bool say_ok = false ) {
if ( * cmd = = ' ; ' | | commands_in_queue > = BUFSIZE ) return false ;
if ( * cmd = = ' ; ' | | commands_in_queue > = BUFSIZE ) return false ;
strcpy ( command_queue [ cmd_queue_index_w ] , cmd ) ;
_commit_command ( say_ok ) ;
return true ;
}
// This is dangerous if a mixing of serial and this happens
/**
char * command = command_queue [ cmd_queue_index_w ] ;
* Enqueue with Serial Echo
strcpy ( command , cmd ) ;
*/
bool enqueue_and_echo_command ( const char * cmd , bool say_ok /*=false*/ ) {
if ( _enqueuecommand ( cmd , say_ok ) ) {
SERIAL_ECHO_START ;
SERIAL_ECHO_START ;
SERIAL_ECHOPGM ( MSG_Enqueueing ) ;
SERIAL_ECHOPGM ( MSG_Enqueueing ) ;
SERIAL_ECHO ( c o mman d) ;
SERIAL_ECHO ( c md) ;
SERIAL_ECHOLNPGM ( " \" " ) ;
SERIAL_ECHOLNPGM ( " \" " ) ;
cmd_queue_index_w = ( cmd_queue_index_w + 1 ) % BUFSIZE ;
commands_in_queue + + ;
return true ;
return true ;
}
return false ;
}
}
void setup_killpin ( ) {
void setup_killpin ( ) {
@ -699,9 +707,8 @@ void setup() {
SERIAL_ECHOPGM ( MSG_PLANNER_BUFFER_BYTES ) ;
SERIAL_ECHOPGM ( MSG_PLANNER_BUFFER_BYTES ) ;
SERIAL_ECHOLN ( ( int ) sizeof ( block_t ) * BLOCK_BUFFER_SIZE ) ;
SERIAL_ECHOLN ( ( int ) sizeof ( block_t ) * BLOCK_BUFFER_SIZE ) ;
# if ENABLED(SDSUPPORT)
// Send "ok" after commands by default
for ( int8_t i = 0 ; i < BUFSIZE ; i + + ) fromsd [ i ] = false ;
for ( int8_t i = 0 ; i < BUFSIZE ; i + + ) send_ok [ i ] = true ;
# endif
// loads data from EEPROM if available else uses defaults (and resets step acceleration rate)
// loads data from EEPROM if available else uses defaults (and resets step acceleration rate)
Config_RetrieveSettings ( ) ;
Config_RetrieveSettings ( ) ;
@ -760,7 +767,7 @@ void setup() {
* - Call LCD update
* - Call LCD update
*/
*/
void loop ( ) {
void loop ( ) {
if ( commands_in_queue < BUFSIZE - 1 ) get_command ( ) ;
if ( commands_in_queue < BUFSIZE ) get_command ( ) ;
# if ENABLED(SDSUPPORT)
# if ENABLED(SDSUPPORT)
card . checkautostart ( false ) ;
card . checkautostart ( false ) ;
@ -820,9 +827,12 @@ void gcode_line_error(const char* err, bool doFlush = true) {
*/
*/
void get_command ( ) {
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 ( 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 ;
static millis_t last_command_time = 0 ;
millis_t ms = millis ( ) ;
millis_t ms = millis ( ) ;
@ -837,29 +847,21 @@ void get_command() {
//
//
while ( commands_in_queue < BUFSIZE & & MYSERIAL . available ( ) > 0 ) {
while ( commands_in_queue < BUFSIZE & & MYSERIAL . available ( ) > 0 ) {
# if ENABLED(NO_TIMEOUTS)
char serial_char = MYSERIAL . read ( ) ;
last_command_time = ms ;
# endif
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
serial_comment_mode = false ; // end of line == end of comment
comment_mode = false ;
if ( ! serial_count ) return ; // empty lines just exit
if ( ! serial_count ) return ; // empty lines just exit
char * command = command_queue [ cmd_queue_index_w ] ;
serial_line_buffer [ serial_count ] = 0 ; // terminate string
command[ serial_count] = 0 ; // te rminat e string
serial_count = 0 ; // rese t buffe r
// this item in the queue is not from sd
char * command = serial_line_buffer ;
# if ENABLED(SDSUPPORT)
fromsd [ cmd_queue_index_w ] = false ;
# endif
while ( * command = = ' ' ) command + + ; // skip any leading spaces
while ( * command = = ' ' ) command + + ; // skip any leading spaces
char * npos = ( * command = = ' N ' ) ? command : NULL ; // Require the N parameter to start the line
char * npos = ( * command = = ' N ' ) ? command : NULL ; // Require the N parameter to start the line
@ -924,44 +926,56 @@ void get_command() {
// If command was e-stop process now
// If command was e-stop process now
if ( strcmp ( command , " M112 " ) = = 0 ) kill ( PSTR ( MSG_KILLED ) ) ;
if ( strcmp ( command , " M112 " ) = = 0 ) kill ( PSTR ( MSG_KILLED ) ) ;
cmd_queue_index_w = ( cmd_queue_index_w + 1 ) % BUFSIZE ;
# if defined(NO_TIMEOUTS) && NO_TIMEOUTS > 0
commands_in_queue + = 1 ;
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
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
// if we have one more character, copy it over
serial_char = MYSERIAL . read ( ) ;
serial_char = MYSERIAL . read ( ) ;
command_queue[ cmd_queue_index_w ] [ serial_count + + ] = serial_char ;
serial_line_buffer [ serial_count + + ] = serial_char ;
}
}
// otherwise do nothing
// otherwise do nothing
}
}
else { // its not a newline, carriage return or escape char
else { // it's not a newline, carriage return or escape char
if ( serial_char = = ' ; ' ) comment_mode = true ;
if ( serial_char = = ' ; ' ) serial_comment_mode = true ;
if ( ! comment_mode ) command_queue [ cmd_queue_index_w ] [ serial_count + + ] = serial_char ;
if ( ! serial_comment_mode ) serial_line_buffer [ serial_count + + ] = serial_char ;
}
}
}
} // queue has space, serial has data
# if ENABLED(SDSUPPORT)
# 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
// '#' 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 r u n dry.
// this character _can_ occur in serial com, due to checksums. however, no checksums are used in SD printing
// 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 ;
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 ( ) ;
int16_t n = card . get ( ) ;
serial_char = ( char ) n ;
char sd_char = ( char ) n ;
if ( serial_char = = ' \n ' | | serial_char = = ' \r ' | |
card_eof = card . eof ( ) ;
( ( serial_char = = ' # ' | | serial_char = = ' : ' ) & & ! comment_mode ) | |
if ( card_eof | | n = = - 1
serial_count > = ( MAX_CMD_SIZE - 1 ) | | 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 ) ;
SERIAL_PROTOCOLLNPGM ( MSG_FILE_PRINTED ) ;
print_job_stop_ms = millis ( ) ;
print_job_stop_ms = millis ( ) ;
char time [ 30 ] ;
char time [ 30 ] ;
@ -974,24 +988,24 @@ void get_command() {
card . printingHasFinished ( ) ;
card . printingHasFinished ( ) ;
card . checkautostart ( true ) ;
card . checkautostart ( true ) ;
}
}
if ( serial_char = = ' # ' ) stop_buffering = true ;
if ( sd_char = = ' # ' ) stop_buffering = true ;
sd_comment_mode = false ; //for new command
if ( ! serial_count ) {
if ( ! sd_count ) continue ; //skip empty lines
comment_mode = false ; //for new command
return ; //if empty line
command_queue [ cmd_queue_index_w ] [ sd_count ] = ' \0 ' ; //terminate string
sd_count = 0 ; //clear buffer
_commit_command ( false ) ;
}
}
command_queue [ cmd_queue_index_w ] [ serial_count ] = 0 ; //terminate string
else if ( sd_count > = MAX_CMD_SIZE - 1 ) {
// if (!comment_mode) {
// Keep fetching, but ignore normal characters beyond the max length
fromsd [ cmd_queue_index_w ] = true ;
// The command will be injected when EOL is reached
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
}
}
else {
else {
if ( s erial _char = = ' ; ' ) comment_mode = true ;
if ( sd_char = = ' ; ' ) sd_comment_mode = true ;
if ( ! comment_mode) command_queue [ cmd_queue_index_w ] [ s erial_count+ + ] = serial _char;
if ( ! sd_comment_mode ) command_queue [ cmd_queue_index_w ] [ sd_count + + ] = sd_char ;
}
}
}
}
@ -2703,7 +2717,7 @@ inline void gcode_G28() {
case MeshStart :
case MeshStart :
mbl . reset ( ) ;
mbl . reset ( ) ;
probe_point = 0 ;
probe_point = 0 ;
enqueue commands_P( PSTR ( " G28 \n G29 S2 " ) ) ;
enqueue _and_echo_ commands_P( PSTR ( " G28 \n G29 S2 " ) ) ;
break ;
break ;
case MeshNext :
case MeshNext :
@ -2742,7 +2756,7 @@ inline void gcode_G28() {
SERIAL_PROTOCOLLNPGM ( " Mesh probing done. " ) ;
SERIAL_PROTOCOLLNPGM ( " Mesh probing done. " ) ;
probe_point = - 1 ;
probe_point = - 1 ;
mbl . active = 1 ;
mbl . active = 1 ;
enqueue commands_P( PSTR ( " G28 " ) ) ;
enqueue _and_echo_ commands_P( PSTR ( " G28 " ) ) ;
}
}
break ;
break ;
@ -3264,7 +3278,7 @@ inline void gcode_G28() {
SERIAL_ECHOLNPGM ( Z_PROBE_END_SCRIPT ) ;
SERIAL_ECHOLNPGM ( Z_PROBE_END_SCRIPT ) ;
}
}
# endif
# endif
enqueue commands_P( PSTR ( Z_PROBE_END_SCRIPT ) ) ;
enqueue _and_echo_ commands_P( PSTR ( Z_PROBE_END_SCRIPT ) ) ;
st_synchronize ( ) ;
st_synchronize ( ) ;
# endif
# endif
@ -3429,7 +3443,7 @@ inline void gcode_M17() {
}
}
/**
/**
* M23 : Select a file
* M23 : Open a file
*/
*/
inline void gcode_M23 ( ) {
inline void gcode_M23 ( ) {
card . openFile ( current_command_args , true ) ;
card . openFile ( current_command_args , true ) ;
@ -5301,7 +5315,7 @@ inline void gcode_M428() {
SERIAL_ERRORLNPGM ( MSG_ERR_M428_TOO_FAR ) ;
SERIAL_ERRORLNPGM ( MSG_ERR_M428_TOO_FAR ) ;
LCD_ALERTMESSAGEPGM ( " Err: Too far! " ) ;
LCD_ALERTMESSAGEPGM ( " Err: Too far! " ) ;
# if HAS_BUZZER
# if HAS_BUZZER
enqueue commands_P( PSTR ( " M300 S40 P200 " ) ) ;
enqueue _and_echo_ commands_P( PSTR ( " M300 S40 P200 " ) ) ;
# endif
# endif
err = true ;
err = true ;
break ;
break ;
@ -5315,7 +5329,7 @@ inline void gcode_M428() {
sync_plan_position ( ) ;
sync_plan_position ( ) ;
LCD_ALERTMESSAGEPGM ( " Offset applied. " ) ;
LCD_ALERTMESSAGEPGM ( " Offset applied. " ) ;
# if HAS_BUZZER
# if HAS_BUZZER
enqueue commands_P( PSTR ( " M300 S659 P200 \n M300 S698 P200 " ) ) ;
enqueue _and_echo_ commands_P( PSTR ( " M300 S659 P200 \n M300 S698 P200 " ) ) ;
# endif
# endif
}
}
}
}
@ -6365,9 +6379,7 @@ void FlushSerialRequestResend() {
void ok_to_send ( ) {
void ok_to_send ( ) {
refresh_cmd_timeout ( ) ;
refresh_cmd_timeout ( ) ;
# if ENABLED(SDSUPPORT)
if ( ! send_ok [ cmd_queue_index_r ] ) return ;
if ( fromsd [ cmd_queue_index_r ] ) return ;
# endif
SERIAL_PROTOCOLPGM ( MSG_OK ) ;
SERIAL_PROTOCOLPGM ( MSG_OK ) ;
# if ENABLED(ADVANCED_OK)
# if ENABLED(ADVANCED_OK)
char * p = command_queue [ cmd_queue_index_r ] ;
char * p = command_queue [ cmd_queue_index_r ] ;
@ -7067,7 +7079,7 @@ void manage_inactivity(bool ignore_stepper_queue/*=false*/) {
filrunout ( ) ;
filrunout ( ) ;
# endif
# endif
if ( commands_in_queue < BUFSIZE - 1 ) get_command ( ) ;
if ( commands_in_queue < BUFSIZE ) get_command ( ) ;
millis_t ms = millis ( ) ;
millis_t ms = millis ( ) ;
@ -7124,7 +7136,7 @@ void manage_inactivity(bool ignore_stepper_queue/*=false*/) {
const int HOME_DEBOUNCE_DELAY = 2500 ;
const int HOME_DEBOUNCE_DELAY = 2500 ;
if ( ! READ ( HOME_PIN ) ) {
if ( ! READ ( HOME_PIN ) ) {
if ( ! homeDebounceCount ) {
if ( ! homeDebounceCount ) {
enqueue commands_P( PSTR ( " G28 " ) ) ;
enqueue _and_echo_ commands_P( PSTR ( " G28 " ) ) ;
LCD_MESSAGEPGM ( MSG_AUTO_HOME ) ;
LCD_MESSAGEPGM ( MSG_AUTO_HOME ) ;
}
}
if ( homeDebounceCount < HOME_DEBOUNCE_DELAY )
if ( homeDebounceCount < HOME_DEBOUNCE_DELAY )
@ -7250,7 +7262,7 @@ void kill(const char* lcd_msg) {
void filrunout ( ) {
void filrunout ( ) {
if ( ! filrunoutEnqueued ) {
if ( ! filrunoutEnqueued ) {
filrunoutEnqueued = true ;
filrunoutEnqueued = true ;
enqueue commands_P( PSTR ( FILAMENT_RUNOUT_SCRIPT ) ) ;
enqueue _and_echo_ commands_P( PSTR ( FILAMENT_RUNOUT_SCRIPT ) ) ;
st_synchronize ( ) ;
st_synchronize ( ) ;
}
}
}
}