Fix of a power panic print stop.

This commit is contained in:
bubnikv 2017-09-21 17:50:39 +02:00
parent 641c21a97b
commit 582a6270b0
5 changed files with 144 additions and 87 deletions

View file

@ -356,7 +356,10 @@ const unsigned int dropsegments=5; //everything with less than this number of st
//The ASCII buffer for receiving from the serial: //The ASCII buffer for receiving from the serial:
#define MAX_CMD_SIZE 96 #define MAX_CMD_SIZE 96
#define BUFSIZE 4 #define BUFSIZE 4
#define CMDHDRSIZE 2 // The command header contains the following values:
// 1st byte: the command source (CMDBUFFER_CURRENT_TYPE_USB, CMDBUFFER_CURRENT_TYPE_SDCARD, CMDBUFFER_CURRENT_TYPE_UI or CMDBUFFER_CURRENT_TYPE_CHAINED)
// 2nd and 3rd byte (LSB first) contains a 16bit length of a command including its preceding comments.
#define CMDHDRSIZE 3
// Firmware based and LCD controlled retract // Firmware based and LCD controlled retract

View file

@ -108,8 +108,8 @@ bool cmdqueue_could_enqueue_front(int len_asked)
cmdqueue_pop_front(); cmdqueue_pop_front();
cmdbuffer_front_already_processed = true; cmdbuffer_front_already_processed = true;
} }
if (bufindr == bufindw && buflen > 0) if (bufindr == bufindw && buflen > 0)
// Full buffer. // Full buffer.
return false; return false;
// Adjust the end of the write buffer based on whether a partial line is in the receive buffer. // Adjust the end of the write buffer based on whether a partial line is in the receive buffer.
int endw = (serial_count > 0) ? (bufindw + MAX_CMD_SIZE + 1) : bufindw; int endw = (serial_count > 0) ? (bufindw + MAX_CMD_SIZE + 1) : bufindw;
@ -137,19 +137,21 @@ bool cmdqueue_could_enqueue_front(int len_asked)
return false; return false;
} }
// Could one enqueue a command of lenthg len_asked into the buffer, // Could one enqueue a command of length len_asked into the buffer,
// while leaving CMDBUFFER_RESERVE_FRONT at the start? // while leaving CMDBUFFER_RESERVE_FRONT at the start?
// If yes, adjust bufindw to the new position, where the new command could be enqued. // If yes, adjust bufindw to the new position, where the new command could be enqued.
// len_asked does not contain the zero terminator size. // len_asked does not contain the zero terminator size.
bool cmdqueue_could_enqueue_back(int len_asked) // This function may update bufindw, therefore for the power panic to work, this function must be called
// with the interrupts disabled!
bool cmdqueue_could_enqueue_back(int len_asked, bool atomic_update)
{ {
// MAX_CMD_SIZE has to accommodate the zero terminator. // MAX_CMD_SIZE has to accommodate the zero terminator.
if (len_asked >= MAX_CMD_SIZE) if (len_asked >= MAX_CMD_SIZE)
return false; return false;
if (bufindr == bufindw && buflen > 0) if (bufindr == bufindw && buflen > 0)
// Full buffer. // Full buffer.
return false; return false;
if (serial_count > 0) { if (serial_count > 0) {
// If there is some data stored starting at bufindw, len_asked is certainly smaller than // If there is some data stored starting at bufindw, len_asked is certainly smaller than
@ -172,7 +174,12 @@ bool cmdqueue_could_enqueue_back(int len_asked)
// Mark the rest of the buffer as used. // Mark the rest of the buffer as used.
memset(cmdbuffer+bufindw, 0, sizeof(cmdbuffer)-bufindw); memset(cmdbuffer+bufindw, 0, sizeof(cmdbuffer)-bufindw);
// and point to the start. // and point to the start.
// Be careful! The bufindw needs to be changed atomically for the power panic & filament panic to work.
if (atomic_update)
cli();
bufindw = 0; bufindw = 0;
if (atomic_update)
sei();
return true; return true;
} }
} else { } else {
@ -193,7 +200,12 @@ bool cmdqueue_could_enqueue_back(int len_asked)
// Mark the rest of the buffer as used. // Mark the rest of the buffer as used.
memset(cmdbuffer+bufindw, 0, sizeof(cmdbuffer)-bufindw); memset(cmdbuffer+bufindw, 0, sizeof(cmdbuffer)-bufindw);
// and point to the start. // and point to the start.
// Be careful! The bufindw needs to be changed atomically for the power panic & filament panic to work.
if (atomic_update)
cli();
bufindw = 0; bufindw = 0;
if (atomic_update)
sei();
return true; return true;
} }
} }
@ -337,30 +349,30 @@ void repeatcommand_front()
bool is_buffer_empty() bool is_buffer_empty()
{ {
if (buflen == 0) return true; if (buflen == 0) return true;
else return false; else return false;
} }
void get_command() void get_command()
{ {
// Test and reserve space for the new command string. // Test and reserve space for the new command string.
if (!cmdqueue_could_enqueue_back(MAX_CMD_SIZE - 1)) if (! cmdqueue_could_enqueue_back(MAX_CMD_SIZE - 1, true))
return; return;
bool rx_buffer_full = false; //flag that serial rx buffer is full bool rx_buffer_full = false; //flag that serial rx buffer is full
while (MYSERIAL.available() > 0) { while (MYSERIAL.available() > 0) {
if (MYSERIAL.available() == RX_BUFFER_SIZE - 1) { //compare number of chars buffered in rx buffer with rx buffer size if (MYSERIAL.available() == RX_BUFFER_SIZE - 1) { //compare number of chars buffered in rx buffer with rx buffer size
SERIAL_ECHOLNPGM("Full RX Buffer"); //if buffer was full, there is danger that reading of last gcode will not be completed SERIAL_ECHOLNPGM("Full RX Buffer"); //if buffer was full, there is danger that reading of last gcode will not be completed
rx_buffer_full = true; //sets flag that buffer was full rx_buffer_full = true; //sets flag that buffer was full
} }
char serial_char = MYSERIAL.read(); char serial_char = MYSERIAL.read();
if (selectedSerialPort == 1) if (selectedSerialPort == 1)
{ {
selectedSerialPort = 0; selectedSerialPort = 0;
MYSERIAL.write(serial_char); // for debuging serial line 2 in farm_mode MYSERIAL.write(serial_char); // for debuging serial line 2 in farm_mode
selectedSerialPort = 1; selectedSerialPort = 1;
} }
TimeSent = millis(); TimeSent = millis();
TimeNow = millis(); TimeNow = millis();
@ -443,10 +455,10 @@ void get_command()
} }
} // end of '*' command } // end of '*' command
if ((strchr_pointer = strchr(cmdbuffer+bufindw+CMDHDRSIZE, 'G')) != NULL) { if ((strchr_pointer = strchr(cmdbuffer+bufindw+CMDHDRSIZE, 'G')) != NULL) {
if (! IS_SD_PRINTING) { if (! IS_SD_PRINTING) {
usb_printing_counter = 10; usb_printing_counter = 10;
is_usb_printing = true; is_usb_printing = true;
} }
if (Stopped == true) { if (Stopped == true) {
int gcode = strtol(strchr_pointer+1, NULL, 10); int gcode = strtol(strchr_pointer+1, NULL, 10);
if (gcode >= 0 && gcode <= 3) { if (gcode >= 0 && gcode <= 3) {
@ -481,7 +493,7 @@ void get_command()
serial_count = 0; //clear buffer serial_count = 0; //clear buffer
// Don't call cmdqueue_could_enqueue_back if there are no characters waiting // Don't call cmdqueue_could_enqueue_back if there are no characters waiting
// in the queue, as this function will reserve the memory. // in the queue, as this function will reserve the memory.
if (MYSERIAL.available() == 0 || ! cmdqueue_could_enqueue_back(MAX_CMD_SIZE-1)) if (MYSERIAL.available() == 0 || ! cmdqueue_could_enqueue_back(MAX_CMD_SIZE-1, true))
return; return;
} // end of "end of line" processing } // end of "end of line" processing
else { else {
@ -509,12 +521,12 @@ void get_command()
} }
} }
//add comment //add comment
if (rx_buffer_full == true && serial_count > 0) { //if rx buffer was full and string was not properly terminated if (rx_buffer_full == true && serial_count > 0) { //if rx buffer was full and string was not properly terminated
rx_buffer_full = false; rx_buffer_full = false;
bufindw = bufindw - serial_count; //adjust tail of the buffer to prepare buffer for writing new command bufindw = bufindw - serial_count; //adjust tail of the buffer to prepare buffer for writing new command
serial_count = 0; serial_count = 0;
} }
#ifdef SDSUPPORT #ifdef SDSUPPORT
if(!card.sdprinting || serial_count!=0){ if(!card.sdprinting || serial_count!=0){
@ -529,40 +541,46 @@ void get_command()
static bool stop_buffering=false; static bool stop_buffering=false;
if(buflen==0) stop_buffering=false; if(buflen==0) stop_buffering=false;
unsigned char sd_count = 0; union {
struct {
char lo;
char hi;
} lohi;
uint16_t value;
} sd_count;
sd_count.value = 0;
// Reads whole lines from the SD card. Never leaves a half-filled line in the cmdbuffer. // Reads whole lines from the SD card. Never leaves a half-filled line in the cmdbuffer.
while( !card.eof() && !stop_buffering) { while( !card.eof() && !stop_buffering) {
int16_t n=card.get(); int16_t n=card.get();
sd_count++; ++ sd_count.value;
char serial_char = (char)n; char serial_char = (char)n;
if(serial_char == '\n' || if(serial_char == '\n' ||
serial_char == '\r' || serial_char == '\r' ||
(serial_char == '#' && comment_mode == false) || ((serial_char == '#' || serial_char == ':') && comment_mode == false) ||
(serial_char == ':' && comment_mode == false) || serial_count >= (MAX_CMD_SIZE - 1) || n==-1)
serial_count >= (MAX_CMD_SIZE - 1)||n==-1)
{ {
if(card.eof()){ if(card.eof()){
SERIAL_PROTOCOLLNRPGM(MSG_FILE_PRINTED); SERIAL_PROTOCOLLNRPGM(MSG_FILE_PRINTED);
stoptime=millis(); stoptime=millis();
char time[30]; char time[30];
unsigned long t=(stoptime-starttime-pause_time)/1000; unsigned long t=(stoptime-starttime-pause_time)/1000;
pause_time = 0; pause_time = 0;
int hours, minutes; int hours, minutes;
minutes=(t/60)%60; minutes=(t/60)%60;
hours=t/60/60; hours=t/60/60;
save_statistics(total_filament_used, t); save_statistics(total_filament_used, t);
sprintf_P(time, PSTR("%i hours %i minutes"),hours, minutes); sprintf_P(time, PSTR("%i hours %i minutes"),hours, minutes);
SERIAL_ECHO_START; SERIAL_ECHO_START;
SERIAL_ECHOLN(time); SERIAL_ECHOLN(time);
lcd_setstatus(time); lcd_setstatus(time);
card.printingHasFinished(); card.printingHasFinished();
card.checkautostart(true); card.checkautostart(true);
if (farm_mode) if (farm_mode)
{ {
prusa_statistics(6); prusa_statistics(6);
lcd_commands_type = LCD_COMMAND_FARM_MODE_CONFIRM; lcd_commands_type = LCD_COMMAND_FARM_MODE_CONFIRM;
} }
} }
if(serial_char=='#') if(serial_char=='#')
@ -570,40 +588,50 @@ void get_command()
if(!serial_count) if(!serial_count)
{ {
comment_mode = false; //for new command // This is either an empty line, or a line with just a comment.
return; //if empty line // Continue to the following line, and continue accumulating the number of bytes
// read from the sdcard into sd_count,
// so that the lenght of the already read empty lines and comments will be added
// to the following non-empty line.
comment_mode = false;
continue; //if empty line
} }
// The new command buffer could be updated non-atomically, because it is not yet considered
// to be inside the active queue.
cmdbuffer[bufindw] = CMDBUFFER_CURRENT_TYPE_SDCARD;
cmdbuffer[bufindw+1] = sd_count.lohi.lo;
cmdbuffer[bufindw+2] = sd_count.lohi.hi;
cmdbuffer[bufindw+serial_count+CMDHDRSIZE] = 0; //terminate string cmdbuffer[bufindw+serial_count+CMDHDRSIZE] = 0; //terminate string
uint8_t len = strlen(cmdbuffer+bufindw+CMDHDRSIZE) + (1 + CMDHDRSIZE); // Calculate the length before disabling the interrupts.
uint8_t len = strlen(cmdbuffer+bufindw+CMDHDRSIZE) + (1 + CMDHDRSIZE);
cli(); /* SERIAL_ECHOPGM("SD cmd(");
cmdbuffer[bufindw] = CMDBUFFER_CURRENT_TYPE_SDCARD; MYSERIAL.print(sd_count.value, DEC);
cmdbuffer[bufindw+1] = sd_count; SERIAL_ECHOPGM(") ");
/* SERIAL_ECHOPGM("SD cmd("); SERIAL_ECHOLN(cmdbuffer+bufindw+CMDHDRSIZE);*/
MYSERIAL.print(sd_count, DEC); // SERIAL_ECHOPGM("cmdbuffer:");
SERIAL_ECHOPGM(") "); // MYSERIAL.print(cmdbuffer);
SERIAL_ECHOLN(cmdbuffer+bufindw+CMDHDRSIZE);*/ // SERIAL_ECHOPGM("buflen:");
// SERIAL_ECHOPGM("cmdbuffer:"); // MYSERIAL.print(buflen+1);
// MYSERIAL.print(cmdbuffer);
cli();
++ buflen; ++ buflen;
// SERIAL_ECHOPGM("buflen:");
// MYSERIAL.print(buflen);
bufindw += len; bufindw += len;
sdpos_atomic = card.get_sdpos(); sdpos_atomic = card.get_sdpos();
if (bufindw == sizeof(cmdbuffer)) if (bufindw == sizeof(cmdbuffer))
bufindw = 0; bufindw = 0;
sei(); sei();
comment_mode = false; //for new command comment_mode = false; //for new command
serial_count = 0; //clear buffer serial_count = 0; //clear buffer
// The following line will reserve buffer space if available. // The following line will reserve buffer space if available.
if (! cmdqueue_could_enqueue_back(MAX_CMD_SIZE-1)) if (! cmdqueue_could_enqueue_back(MAX_CMD_SIZE-1, true))
return; return;
} }
else else
{ {
if(serial_char == ';') comment_mode = true; if(serial_char == ';') comment_mode = true;
if(!comment_mode) cmdbuffer[bufindw+CMDHDRSIZE+serial_count++] = serial_char; else if(!comment_mode) cmdbuffer[bufindw+CMDHDRSIZE+serial_count++] = serial_char;
} }
} }
@ -612,17 +640,26 @@ void get_command()
uint16_t cmdqueue_calc_sd_length() uint16_t cmdqueue_calc_sd_length()
{ {
int _buflen = buflen; int _buflen = buflen;
int _bufindr = bufindr; int _bufindr = bufindr;
uint16_t sdlen = 0; union {
while (_buflen--) struct {
{ char lo;
if (cmdbuffer[_bufindr] == CMDBUFFER_CURRENT_TYPE_SDCARD) char hi;
sdlen += cmdbuffer[_bufindr + 1]; } lohi;
//skip header, skip command uint16_t value;
for (_bufindr += CMDHDRSIZE; cmdbuffer[_bufindr] != 0; ++ _bufindr) ; } sdlen;
//skip zeros sdlen.value = 0;
for (++ _bufindr; _bufindr < sizeof(cmdbuffer) && cmdbuffer[_bufindr] == 0; ++ _bufindr) ; while (_buflen--)
} {
return sdlen; if (cmdbuffer[_bufindr] == CMDBUFFER_CURRENT_TYPE_SDCARD) {
} sdlen.lohi.lo += cmdbuffer[_bufindr + 1];
sdlen.lohi.hi += cmdbuffer[_bufindr + 2];
}
//skip header, skip command
for (_bufindr += CMDHDRSIZE; cmdbuffer[_bufindr] != 0; ++ _bufindr) ;
//skip zeros
for (++ _bufindr; _bufindr < sizeof(cmdbuffer) && cmdbuffer[_bufindr] == 0; ++ _bufindr) ;
}
return sdlen.value;
}

View file

@ -54,9 +54,11 @@ extern long Stopped_gcode_LastN;
extern bool cmdqueue_pop_front(); extern bool cmdqueue_pop_front();
extern void cmdqueue_reset(); extern void cmdqueue_reset();
extern bool cmdqueue_could_enqueue_front(int len_asked); extern bool cmdqueue_could_enqueue_front(int len_asked);
extern bool cmdqueue_could_enqueue_back(int len_asked); extern bool cmdqueue_could_enqueue_back(int len_asked, bool atomic_update = false);
#ifdef CMDBUFFER_DEBUG
extern void cmdqueue_dump_to_serial_single_line(int nr, const char *p); extern void cmdqueue_dump_to_serial_single_line(int nr, const char *p);
extern void cmdqueue_dump_to_serial(); extern void cmdqueue_dump_to_serial();
#endif /* CMDBUFFER_DEBUG */
extern void enquecommand(const char *cmd, bool from_progmem); extern void enquecommand(const char *cmd, bool from_progmem);
extern void enquecommand_front(const char *cmd, bool from_progmem); extern void enquecommand_front(const char *cmd, bool from_progmem);
extern void repeatcommand_front(); extern void repeatcommand_front();

View file

@ -1300,9 +1300,17 @@ void planner_queue_min_reset()
} }
#endif /* PLANNER_DIAGNOSTICS */ #endif /* PLANNER_DIAGNOSTICS */
void planner_add_sd_length(uint8_t sdlen) void planner_add_sd_length(uint16_t sdlen)
{ {
block_buffer[block_buffer_tail].sdlen += sdlen; if (block_buffer_head != block_buffer_tail) {
// The planner buffer is not empty. Get the index of the last buffer line entered,
// which is (block_buffer_head - 1) modulo BLOCK_BUFFER_SIZE.
unsigned char last = (block_buffer_head + BLOCK_BUFFER_SIZE - 1) & (BLOCK_BUFFER_SIZE - 1);
block_buffer[last].sdlen += sdlen;
} else {
// There is no line stored in the planner buffer, which means the last command does not need to be revertible,
// at a power panic, so the length of this command may be forgotten.
}
} }
uint16_t planner_calc_sd_length() uint16_t planner_calc_sd_length()

View file

@ -159,7 +159,11 @@ extern unsigned long axis_steps_per_sqr_second[NUM_AXIS];
extern block_t block_buffer[BLOCK_BUFFER_SIZE]; // A ring buffer for motion instfructions extern block_t block_buffer[BLOCK_BUFFER_SIZE]; // A ring buffer for motion instfructions
extern volatile unsigned char block_buffer_head; // Index of the next block to be pushed // Index of the next block to be pushed into the planner queue.
extern volatile unsigned char block_buffer_head;
// Index of the first block in the planner queue.
// This is the block, which is being currently processed by the stepper routine,
// or which is first to be processed by the stepper routine.
extern volatile unsigned char block_buffer_tail; extern volatile unsigned char block_buffer_tail;
// Called when the current block is no longer needed. Discards the block and makes the memory // Called when the current block is no longer needed. Discards the block and makes the memory
// available for new blocks. // available for new blocks.
@ -170,7 +174,10 @@ FORCE_INLINE void plan_discard_current_block()
} }
} }
// Gets the current block. Returns NULL if buffer empty // Gets the current block. This is the block to be exectuted by the stepper routine.
// Mark this block as busy, so its velocities and acceperations will be no more recalculated
// by the planner routine.
// Returns NULL if buffer empty
FORCE_INLINE block_t *plan_get_current_block() FORCE_INLINE block_t *plan_get_current_block()
{ {
if (block_buffer_head == block_buffer_tail) { if (block_buffer_head == block_buffer_tail) {
@ -220,6 +227,6 @@ extern uint8_t planner_queue_min();
extern void planner_queue_min_reset(); extern void planner_queue_min_reset();
#endif /* PLANNER_DIAGNOSTICS */ #endif /* PLANNER_DIAGNOSTICS */
extern void planner_add_sd_length(uint8_t sdlen); extern void planner_add_sd_length(uint16_t sdlen);
extern uint16_t planner_calc_sd_length(); extern uint16_t planner_calc_sd_length();