diff --git a/Firmware/Configuration_adv.h b/Firmware/Configuration_adv.h index d0cc5319..7d2d5288 100644 --- a/Firmware/Configuration_adv.h +++ b/Firmware/Configuration_adv.h @@ -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: #define MAX_CMD_SIZE 96 #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 diff --git a/Firmware/cmdqueue.cpp b/Firmware/cmdqueue.cpp index 252af7f7..7f788756 100644 --- a/Firmware/cmdqueue.cpp +++ b/Firmware/cmdqueue.cpp @@ -108,8 +108,8 @@ bool cmdqueue_could_enqueue_front(int len_asked) cmdqueue_pop_front(); cmdbuffer_front_already_processed = true; } - if (bufindr == bufindw && buflen > 0) - // Full buffer. + if (bufindr == bufindw && buflen > 0) + // Full buffer. return false; // 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; @@ -137,19 +137,21 @@ bool cmdqueue_could_enqueue_front(int len_asked) 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? // If yes, adjust bufindw to the new position, where the new command could be enqued. // 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. if (len_asked >= MAX_CMD_SIZE) return false; - if (bufindr == bufindw && buflen > 0) - // Full buffer. - return false; + if (bufindr == bufindw && buflen > 0) + // Full buffer. + return false; if (serial_count > 0) { // 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. memset(cmdbuffer+bufindw, 0, sizeof(cmdbuffer)-bufindw); // 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; + if (atomic_update) + sei(); return true; } } else { @@ -193,7 +200,12 @@ bool cmdqueue_could_enqueue_back(int len_asked) // Mark the rest of the buffer as used. memset(cmdbuffer+bufindw, 0, sizeof(cmdbuffer)-bufindw); // 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; + if (atomic_update) + sei(); return true; } } @@ -337,30 +349,30 @@ void repeatcommand_front() bool is_buffer_empty() { - if (buflen == 0) return true; - else return false; + if (buflen == 0) return true; + else return false; } void get_command() { // Test and reserve space for the new command string. - if (!cmdqueue_could_enqueue_back(MAX_CMD_SIZE - 1)) - return; - - bool rx_buffer_full = false; //flag that serial rx buffer is full + if (! cmdqueue_could_enqueue_back(MAX_CMD_SIZE - 1, true)) + return; + + bool rx_buffer_full = false; //flag that serial rx buffer is full while (MYSERIAL.available() > 0) { - 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 - rx_buffer_full = true; //sets flag that buffer was full - } + 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 + rx_buffer_full = true; //sets flag that buffer was full + } char serial_char = MYSERIAL.read(); - if (selectedSerialPort == 1) - { - selectedSerialPort = 0; - MYSERIAL.write(serial_char); // for debuging serial line 2 in farm_mode - selectedSerialPort = 1; - } + if (selectedSerialPort == 1) + { + selectedSerialPort = 0; + MYSERIAL.write(serial_char); // for debuging serial line 2 in farm_mode + selectedSerialPort = 1; + } TimeSent = millis(); TimeNow = millis(); @@ -443,10 +455,10 @@ void get_command() } } // end of '*' command if ((strchr_pointer = strchr(cmdbuffer+bufindw+CMDHDRSIZE, 'G')) != NULL) { - if (! IS_SD_PRINTING) { - usb_printing_counter = 10; - is_usb_printing = true; - } + if (! IS_SD_PRINTING) { + usb_printing_counter = 10; + is_usb_printing = true; + } if (Stopped == true) { int gcode = strtol(strchr_pointer+1, NULL, 10); if (gcode >= 0 && gcode <= 3) { @@ -481,7 +493,7 @@ void get_command() serial_count = 0; //clear buffer // Don't call cmdqueue_could_enqueue_back if there are no characters waiting // 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; } // end of "end of line" processing else { @@ -509,12 +521,12 @@ void get_command() } } - //add comment - if (rx_buffer_full == true && serial_count > 0) { //if rx buffer was full and string was not properly terminated - rx_buffer_full = false; - bufindw = bufindw - serial_count; //adjust tail of the buffer to prepare buffer for writing new command - serial_count = 0; - } + //add comment + if (rx_buffer_full == true && serial_count > 0) { //if rx buffer was full and string was not properly terminated + rx_buffer_full = false; + bufindw = bufindw - serial_count; //adjust tail of the buffer to prepare buffer for writing new command + serial_count = 0; + } #ifdef SDSUPPORT if(!card.sdprinting || serial_count!=0){ @@ -529,40 +541,46 @@ void get_command() static bool 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. while( !card.eof() && !stop_buffering) { int16_t n=card.get(); - sd_count++; + ++ sd_count.value; char serial_char = (char)n; if(serial_char == '\n' || serial_char == '\r' || - (serial_char == '#' && comment_mode == false) || - (serial_char == ':' && comment_mode == false) || - serial_count >= (MAX_CMD_SIZE - 1)||n==-1) + ((serial_char == '#' || serial_char == ':') && comment_mode == false) || + serial_count >= (MAX_CMD_SIZE - 1) || n==-1) { if(card.eof()){ SERIAL_PROTOCOLLNRPGM(MSG_FILE_PRINTED); stoptime=millis(); char time[30]; unsigned long t=(stoptime-starttime-pause_time)/1000; - pause_time = 0; + pause_time = 0; int hours, minutes; minutes=(t/60)%60; hours=t/60/60; - save_statistics(total_filament_used, t); - sprintf_P(time, PSTR("%i hours %i minutes"),hours, minutes); + save_statistics(total_filament_used, t); + sprintf_P(time, PSTR("%i hours %i minutes"),hours, minutes); SERIAL_ECHO_START; SERIAL_ECHOLN(time); lcd_setstatus(time); card.printingHasFinished(); card.checkautostart(true); - if (farm_mode) - { - prusa_statistics(6); - lcd_commands_type = LCD_COMMAND_FARM_MODE_CONFIRM; - } + if (farm_mode) + { + prusa_statistics(6); + lcd_commands_type = LCD_COMMAND_FARM_MODE_CONFIRM; + } } if(serial_char=='#') @@ -570,40 +588,50 @@ void get_command() if(!serial_count) { - comment_mode = false; //for new command - return; //if empty line + // This is either an empty line, or a line with just a comment. + // 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 - 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(); - cmdbuffer[bufindw] = CMDBUFFER_CURRENT_TYPE_SDCARD; - cmdbuffer[bufindw+1] = sd_count; -/* SERIAL_ECHOPGM("SD cmd("); - MYSERIAL.print(sd_count, DEC); - SERIAL_ECHOPGM(") "); - SERIAL_ECHOLN(cmdbuffer+bufindw+CMDHDRSIZE);*/ -// SERIAL_ECHOPGM("cmdbuffer:"); -// MYSERIAL.print(cmdbuffer); +/* SERIAL_ECHOPGM("SD cmd("); + MYSERIAL.print(sd_count.value, DEC); + SERIAL_ECHOPGM(") "); + SERIAL_ECHOLN(cmdbuffer+bufindw+CMDHDRSIZE);*/ +// SERIAL_ECHOPGM("cmdbuffer:"); +// MYSERIAL.print(cmdbuffer); +// SERIAL_ECHOPGM("buflen:"); +// MYSERIAL.print(buflen+1); + + cli(); ++ buflen; -// SERIAL_ECHOPGM("buflen:"); -// MYSERIAL.print(buflen); bufindw += len; - sdpos_atomic = card.get_sdpos(); + sdpos_atomic = card.get_sdpos(); if (bufindw == sizeof(cmdbuffer)) bufindw = 0; - sei(); + sei(); - comment_mode = false; //for new command + comment_mode = false; //for new command serial_count = 0; //clear buffer // 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; } else { 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() { - int _buflen = buflen; - int _bufindr = bufindr; - uint16_t sdlen = 0; - while (_buflen--) - { - if (cmdbuffer[_bufindr] == CMDBUFFER_CURRENT_TYPE_SDCARD) - sdlen += cmdbuffer[_bufindr + 1]; - //skip header, skip command - for (_bufindr += CMDHDRSIZE; cmdbuffer[_bufindr] != 0; ++ _bufindr) ; - //skip zeros - for (++ _bufindr; _bufindr < sizeof(cmdbuffer) && cmdbuffer[_bufindr] == 0; ++ _bufindr) ; - } - return sdlen; -} + int _buflen = buflen; + int _bufindr = bufindr; + union { + struct { + char lo; + char hi; + } lohi; + uint16_t value; + } sdlen; + sdlen.value = 0; + while (_buflen--) + { + 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; +} \ No newline at end of file diff --git a/Firmware/cmdqueue.h b/Firmware/cmdqueue.h index adeaf6b5..5ee58a59 100644 --- a/Firmware/cmdqueue.h +++ b/Firmware/cmdqueue.h @@ -54,9 +54,11 @@ extern long Stopped_gcode_LastN; extern bool cmdqueue_pop_front(); extern void cmdqueue_reset(); 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(); +#endif /* CMDBUFFER_DEBUG */ extern void enquecommand(const char *cmd, bool from_progmem); extern void enquecommand_front(const char *cmd, bool from_progmem); extern void repeatcommand_front(); diff --git a/Firmware/planner.cpp b/Firmware/planner.cpp index e5eb41db..b45aa69b 100644 --- a/Firmware/planner.cpp +++ b/Firmware/planner.cpp @@ -1300,9 +1300,17 @@ void planner_queue_min_reset() } #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() diff --git a/Firmware/planner.h b/Firmware/planner.h index 0dd831bb..3b9e65a1 100644 --- a/Firmware/planner.h +++ b/Firmware/planner.h @@ -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 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; // Called when the current block is no longer needed. Discards the block and makes the memory // 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() { if (block_buffer_head == block_buffer_tail) { @@ -220,6 +227,6 @@ extern uint8_t planner_queue_min(); extern void planner_queue_min_reset(); #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();