Quellcode durchsuchen

Fix of a power panic print stop.

bubnikv vor 6 Jahren
Ursprung
Commit
582a6270b0
5 geänderte Dateien mit 145 neuen und 88 gelöschten Zeilen
  1. 4 1
      Firmware/Configuration_adv.h
  2. 118 81
      Firmware/cmdqueue.cpp
  3. 3 1
      Firmware/cmdqueue.h
  4. 10 2
      Firmware/planner.cpp
  5. 10 3
      Firmware/planner.h

+ 4 - 1
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

+ 118 - 81
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);
-
-	  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);
+      // Calculate the length before disabling the interrupts.
+      uint8_t len = strlen(cmdbuffer+bufindw+CMDHDRSIZE) + (1 + CMDHDRSIZE);
+
+/*    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;
+}

+ 3 - 1
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();

+ 10 - 2
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()

+ 10 - 3
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();