Browse Source

merge changes from upstream

PavelSindler 5 năm trước cách đây
mục cha
commit
7e3a1c7d45

+ 6 - 5
.travis.yml

@@ -3,16 +3,17 @@ before_install:
   - sudo apt-get install -y ninja-build
 script:
   - bash -x test.sh
-  - bash -x build.sh
+  - cp Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h Firmware/Configuration_prusa.h
+  - bash -x build.sh || { echo "1_75mm_MK3-EINSy10a-E3Dv6full variant failed" && false; }
   - rm Firmware/Configuration_prusa.h
   - cp Firmware/variants/1_75mm_MK25-RAMBo13a-E3Dv6full.h Firmware/Configuration_prusa.h
-  - bash -x build.sh
+  - bash -x build.sh || { echo "1_75mm_MK25-RAMBo13a-E3Dv6full variant failed" && false; }
   - rm Firmware/Configuration_prusa.h
   - cp Firmware/variants/1_75mm_MK25-RAMBo10a-E3Dv6full.h Firmware/Configuration_prusa.h
-  - bash -x build.sh
+  - bash -x build.sh || { echo "1_75mm_MK25-RAMBo10a-E3Dv6full variant failed" && false; }
   - rm Firmware/Configuration_prusa.h
   - cp Firmware/variants/1_75mm_MK2-RAMBo13a-E3Dv6full.h Firmware/Configuration_prusa.h
-  - bash -x build.sh
+  - bash -x build.sh || { echo "1_75mm_MK2-RAMBo13a-E3Dv6full variant failed" && false; }
   - rm Firmware/Configuration_prusa.h
   - cp Firmware/variants/1_75mm_MK2-RAMBo10a-E3Dv6full.h Firmware/Configuration_prusa.h
-  - bash -x build.sh
+  - bash -x build.sh || { echo "1_75mm_MK2-RAMBo10a-E3Dv6full variant failed" && false; }

+ 2 - 0
CMakeLists.txt

@@ -14,7 +14,9 @@ set(TEST_SOURCES
 	Tests/tests.cpp
 	Tests/Example_test.cpp
 	Tests/Timer_test.cpp
+	Tests/AutoDeplete_test.cpp
 	Firmware/Timer.cpp
+	Firmware/AutoDeplete.cpp
 )
 add_executable(tests ${TEST_SOURCES})
 target_include_directories(tests PRIVATE Tests)

+ 79 - 0
Firmware/AutoDeplete.cpp

@@ -0,0 +1,79 @@
+//! @file
+//! @author: Marek Bel
+//! @date Jan 3, 2019
+
+#include "AutoDeplete.h"
+#include "assert.h"
+
+//! @brief bit field marking depleted filaments
+//!
+//! binary 1 marks filament as depleted
+//! Zero initialized value means, that no filament is depleted.
+static uint8_t depleted;
+static const uint8_t filamentCount = 5;
+
+//! @return binary 1 for all filaments
+//! @par fCount number of filaments
+static constexpr uint8_t allDepleted(uint8_t fCount)
+{
+    return fCount == 1 ? 1 : ((1 << (fCount - 1)) | allDepleted(fCount - 1));
+}
+
+//! @brief Is filament available for printing?
+//! @par filament Filament number to be checked
+//! @retval true Filament is available for printing.
+//! @retval false Filament is not available for printing.
+static bool loaded(uint8_t filament)
+{
+    if (depleted & (1 << filament)) return false;
+    return true;
+}
+
+//! @brief Mark filament as not available for printing.
+//! @par filament filament to be marked
+void ad_markDepleted(uint8_t filament)
+{
+    assert(filament < filamentCount);
+    if (filament < filamentCount)
+    {
+        depleted |= 1 << filament;
+    }
+}
+
+//! @brief Mark filament as available for printing.
+//! @par filament filament to be marked
+void ad_markLoaded(uint8_t filament)
+{
+    assert(filament < filamentCount);
+    if (filament < filamentCount)
+    {
+        depleted &= ~(1 << filament);
+    }
+}
+
+//! @brief Get alternative filament, which is not depleted
+//! @par filament filament
+//! @return Filament, if it is depleted, returns next available,
+//! if all filaments are depleted, returns filament function parameter.
+uint8_t ad_getAlternative(uint8_t filament)
+{
+    assert(filament < filamentCount);
+    for (uint8_t i = 0; i<filamentCount; ++i)
+    {
+        uint8_t nextFilament = (filament + i) % filamentCount;
+        if (loaded(nextFilament)) return nextFilament;
+    }
+    return filament;
+}
+
+//! @brief Are all filaments depleted?
+//! @retval true All filaments are depleted.
+//! @retval false All filaments are not depleted.
+bool ad_allDepleted()
+{
+    if (allDepleted(filamentCount) == depleted)
+    {
+        return true;
+    }
+    return false;
+}

+ 17 - 0
Firmware/AutoDeplete.h

@@ -0,0 +1,17 @@
+//! @file
+//! @author: Marek Bel
+//! @brief Filament auto deplete engine for multi-material prints with MMUv2 (Now marketed as SpoolJoin)
+//!
+//! Interface for marking MMUv2 filaments as depleted and getting alternative filament for printing.
+
+#ifndef AUTODEPLETE_H
+#define AUTODEPLETE_H
+
+#include <stdint.h>
+
+void ad_markDepleted(uint8_t filament);
+void ad_markLoaded(uint8_t filament);
+uint8_t ad_getAlternative(uint8_t filament);
+bool ad_allDepleted();
+
+#endif /* AUTODEPLETE_H */

+ 1 - 3
Firmware/Configuration.h

@@ -126,13 +126,11 @@
 // Comment the following line to disable PID and enable bang-bang.
 #define PIDTEMP
 #define BANG_MAX 255 // limits current to nozzle while in bang-bang mode; 255=full current
-#define PID_MAX BANG_MAX // limits current to nozzle while PID is active (see PID_FUNCTIONAL_RANGE below); 255=full current
+#define PID_MAX BANG_MAX // limits current to nozzle while PID is active; 255=full current
 #ifdef PIDTEMP
   //#define PID_DEBUG // Sends debug data to the serial port.
   //#define PID_OPENLOOP 1 // Puts PID in open loop. M104/M140 sets the output power from 0 to PID_MAX
   //#define SLOW_PWM_HEATERS // PWM with very low frequency (roughly 0.125Hz=8s) and minimum state time of approximately 1s useful for heaters driven by a relay
-  #define PID_FUNCTIONAL_RANGE 10 // If the temperature difference between the target temperature and the actual temperature
-                                  // is more then PID_FUNCTIONAL_RANGE then the PID will be shut off and the heater will be set to min/max.
   #define PID_INTEGRAL_DRIVE_MAX PID_MAX  //limit for the integral term
   #define K1 0.95 //smoothing factor within the PID
   #define PID_dT ((OVERSAMPLENR * 10.0)/(F_CPU / 64.0 / 256.0)) //sampling period of the temperature routine

+ 6 - 0
Firmware/Marlin_main.cpp

@@ -78,6 +78,7 @@
 #include <avr/pgmspace.h>
 
 #include "Dcodes.h"
+#include "AutoDeplete.h"
 
 
 #ifdef SWSPI
@@ -6947,6 +6948,10 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
           }
           else {
               tmp_extruder = code_value();
+              if (mmu_enabled && lcd_autoDepleteEnabled())
+              {
+                  tmp_extruder = ad_getAlternative(tmp_extruder);
+              }
           }
           st_synchronize();
           snmm_filaments_used |= (1 << tmp_extruder); //for stop print
@@ -7641,6 +7646,7 @@ void Stop()
   disable_heater();
   if(Stopped == false) {
     Stopped = true;
+    lcd_print_stop();
     Stopped_gcode_LastN = gcode_LastN; // Save last g_code for restart
     SERIAL_ERROR_START;
     SERIAL_ERRORLNRPGM(MSG_ERR_STOPPED);

+ 105 - 75
Firmware/mmu.cpp

@@ -1,4 +1,4 @@
-//mmu.cpp
+//! @file
 
 #include "mmu.h"
 #include "planner.h"
@@ -14,6 +14,7 @@
 #include "printers.h"
 #include <avr/pgmspace.h>
 #include "io_atmega2560.h"
+#include "AutoDeplete.h"
 
 #ifdef TMC2130
 #include "tmc2130.h"
@@ -245,7 +246,7 @@ void mmu_loop(void)
 				mmu_printf_P(PSTR("T%d\n"), filament);
 				mmu_state = 3; // wait for response
 				mmu_fil_loaded = true;
-				if(ir_sensor_detected) mmu_idl_sens = 1; //if idler sensor detected, use it for T-code
+				mmu_idl_sens = 1;
 			}
 			else if ((mmu_cmd >= MMU_CMD_L0) && (mmu_cmd <= MMU_CMD_L4))
 			{
@@ -263,7 +264,7 @@ void mmu_loop(void)
 #endif //MMU_DEBUG
 				mmu_puts_P(PSTR("C0\n")); //send 'continue loading'
 				mmu_state = 3;
-				if(ir_sensor_detected) mmu_idl_sens = 1; //if idler sensor detected use it for C0 code
+				mmu_idl_sens = 1;
 			}
 			else if (mmu_cmd == MMU_CMD_U0)
 			{
@@ -326,8 +327,15 @@ void mmu_loop(void)
 			if (!mmu_finda && CHECK_FSENSOR && fsensor_enabled) {
 				fsensor_stop_and_save_print();
 				enquecommand_front_P(PSTR("FSENSOR_RECOVER")); //then recover
-				if (lcd_autoDepleteEnabled()) enquecommand_front_P(PSTR("M600 AUTO")); //save print and run M600 command
-				else enquecommand_front_P(PSTR("M600")); //save print and run M600 command
+				ad_markDepleted(mmu_extruder);
+				if (lcd_autoDepleteEnabled() && !ad_allDepleted())
+				{
+				    enquecommand_front_P(PSTR("M600 AUTO")); //save print and run M600 command
+				}
+				else
+				{
+				    enquecommand_front_P(PSTR("M600")); //save print and run M600 command
+				}
 			}
 			mmu_state = 1;
 			if (mmu_cmd == 0)
@@ -339,19 +347,20 @@ void mmu_loop(void)
 		}
 		return;
 	case 3: //response to mmu commands
-		if (mmu_idl_sens && ir_sensor_detected) {
-			if (PIN_GET(IR_SENSOR_PIN) == 0 && mmu_loading_flag)
-			{
+        if (mmu_idl_sens)
+        {
+            if (PIN_GET(MMU_IDLER_SENSOR_PIN) == 0 && mmu_loading_flag)
+            {
 #ifdef MMU_DEBUG
-					printf_P(PSTR("MMU <= 'A'\n"));
+                printf_P(PSTR("MMU <= 'A'\n"));
 #endif //MMU_DEBUG  
-					mmu_puts_P(PSTR("A\n")); //send 'abort' request
-					mmu_idl_sens = 0;
-					//printf_P(PSTR("MMU IDLER_SENSOR = 0 - ABORT\n"));
-			}
-			//else
-				//printf_P(PSTR("MMU IDLER_SENSOR = 1 - WAIT\n"));
-		}
+                mmu_puts_P(PSTR("A\n")); //send 'abort' request
+                mmu_idl_sens = 0;
+                //printf_P(PSTR("MMU IDLER_SENSOR = 0 - ABORT\n"));
+            }
+            //else
+                //printf_P(PSTR("MMU IDLER_SENSOR = 1 - WAIT\n"));
+        }
 		if (mmu_rx_ok() > 0)
 		{
 #ifdef MMU_DEBUG
@@ -420,69 +429,96 @@ int8_t mmu_set_filament_type(uint8_t extruder, uint8_t filament)
 	return timeout?1:0;
 }
 
+//! @brief Enqueue MMUv2 command
+//!
+//! Call manage_response() after enqueuing to process command.
+//! If T command is enqueued, it disables current for extruder motor if TMC2130 driver present.
+//! If T or L command is enqueued, it marks filament loaded in AutoDeplete module.
 void mmu_command(uint8_t cmd)
 {
-#ifdef TMC2130
 	if ((cmd >= MMU_CMD_T0) && (cmd <= MMU_CMD_T4))
 	{
 		//disable extruder motor
+#ifdef TMC2130
 		tmc2130_set_pwr(E_AXIS, 0);
+#endif //TMC2130
 		//printf_P(PSTR("E-axis disabled\n"));
+		ad_markLoaded(cmd - MMU_CMD_T0);
 	}
-#endif //TMC2130
+    if ((cmd >= MMU_CMD_L0) && (cmd <= MMU_CMD_L4))
+    {
+        ad_markLoaded(cmd - MMU_CMD_L0);
+    }
 
 	mmu_cmd = cmd;
 	mmu_ready = false;
 }
 
-void mmu_load_step() {
+//! @brief Rotate extruder idler to catch filament
+//! @par synchronize
+//!  * true blocking call
+//!  * false non-blocking call
+void mmu_load_step(bool synchronize)
+{
 		current_position[E_AXIS] = current_position[E_AXIS] + MMU_LOAD_FEEDRATE * 0.1;
 		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], MMU_LOAD_FEEDRATE, active_extruder);
-		st_synchronize();
+		if (synchronize) st_synchronize();
+}
+
+//! @brief Is nozzle hot enough to move extruder wheels and do we have idler sensor?
+//!
+//! Do load steps only if temperature is higher then min. temp for safe extrusion and
+//! idler sensor present.
+//! Otherwise "cold extrusion prevented" would be send to serial line periodically
+//! and watchdog reset will be triggered by lack of keep_alive processing.
+//!
+//! @retval true temperature is high enough to move extruder
+//! @retval false temperature is not high enough to move extruder, turned
+//!         off E-stepper to prevent over-heating and allow filament pull-out if necessary
+bool can_extrude()
+{
+    if ((degHotend(active_extruder) < EXTRUDE_MINTEMP) || !mmu_idler_sensor_detected)
+    {
+        disable_e0();
+        delay_keep_alive(100);
+        return false;
+    }
+    return true;
 }
 
 bool mmu_get_response(uint8_t move)
 {
-	mmu_loading_flag = false;
-	if (!ir_sensor_detected) move = MMU_NO_MOVE;
+    mmu_loading_flag = false;
 
 	printf_P(PSTR("mmu_get_response - begin move:%d\n"), move);
 	KEEPALIVE_STATE(IN_PROCESS);
 	while (mmu_cmd != 0)
 	{
-//		mmu_loop();
 		delay_keep_alive(100);
 	}
 
 	while (!mmu_ready)
 	{
-//		mmu_loop();
-
 		if ((mmu_state != 3) && (mmu_last_cmd == 0))
 			break;
 
-		//Do load steps only if temperature is higher then min. temp for safe extrusion.
-		//Otherwise "cold extrusion prevented" would be send to serial line periodically
-		if (degHotend(active_extruder) < EXTRUDE_MINTEMP) {
-			disable_e0(); //turn off E-stepper to prevent overheating and alow filament pull-out if necessary
-			delay_keep_alive(100);
-			continue;
-		}
-
 		switch (move) {
-			case MMU_LOAD_MOVE: 
-				mmu_loading_flag = true;
-				mmu_load_step();
+			case MMU_LOAD_MOVE:
+			    mmu_loading_flag = true;
+				if (can_extrude()) mmu_load_step();
 				//don't rely on "ok" signal from mmu unit; if filament detected by idler sensor during loading stop loading movements to prevent infinite loading
 				if (PIN_GET(IR_SENSOR_PIN) == 0) move = MMU_NO_MOVE;
 				break;
 			case MMU_UNLOAD_MOVE:
-				if (PIN_GET(IR_SENSOR_PIN) == 0) //filament is still detected by idler sensor, printer helps with unlading 
-				{ 
-					printf_P(PSTR("Unload 1\n"));
-					current_position[E_AXIS] = current_position[E_AXIS] - MMU_LOAD_FEEDRATE * MMU_LOAD_TIME_MS*0.001;
-					plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], MMU_LOAD_FEEDRATE, active_extruder);
-					st_synchronize();
+				if (PIN_GET(MMU_IDLER_SENSOR_PIN) == 0) //filament is still detected by idler sensor, printer helps with unlading 
+				{
+				    if (can_extrude())
+				    {
+                        printf_P(PSTR("Unload 1\n"));
+                        current_position[E_AXIS] = current_position[E_AXIS] - MMU_LOAD_FEEDRATE * MMU_LOAD_TIME_MS*0.001;
+                        plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], MMU_LOAD_FEEDRATE, active_extruder);
+                        st_synchronize();
+				    }
 				}
 				else //filament was unloaded from idler, no additional movements needed 
 				{ 
@@ -492,12 +528,15 @@ bool mmu_get_response(uint8_t move)
 				}
 				break;
 			case MMU_TCODE_MOVE: //first do unload and then continue with infinite loading movements
-				if (PIN_GET(IR_SENSOR_PIN) == 0) //filament detected by idler sensor, we must unload first 
-				{ 
-					printf_P(PSTR("Unload 2\n"));
-					current_position[E_AXIS] = current_position[E_AXIS] - MMU_LOAD_FEEDRATE * MMU_LOAD_TIME_MS*0.001;
-					plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], MMU_LOAD_FEEDRATE, active_extruder);
-					st_synchronize();
+				if (PIN_GET(MMU_IDLER_SENSOR_PIN) == 0) //filament detected by idler sensor, we must unload first 
+				{
+                    if (can_extrude())
+                    {
+                        printf_P(PSTR("Unload 2\n"));
+                        current_position[E_AXIS] = current_position[E_AXIS] - MMU_LOAD_FEEDRATE * MMU_LOAD_TIME_MS*0.001;
+                        plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], MMU_LOAD_FEEDRATE, active_extruder);
+                        st_synchronize();
+                    }
 				}
 				else //delay to allow mmu unit to pull out filament from bondtech gears and then start with infinite loading 
 				{ 
@@ -505,6 +544,7 @@ bool mmu_get_response(uint8_t move)
 					disable_e0(); //turn off E-stepper to prevent overheating and alow filament pull-out if necessary
 					delay_keep_alive(MMU_LOAD_TIME_MS);
 					move = MMU_LOAD_MOVE;
+					printf_P(PSTR("mmu_get_response - begin move:%d\n"), move);
 				}
 				break;
 			case MMU_NO_MOVE:
@@ -518,27 +558,20 @@ bool mmu_get_response(uint8_t move)
 	mmu_ready = false;
 //	printf_P(PSTR("mmu_get_response - end %d\n"), ret?1:0);
 	return ret;
-
-/*	//waits for "ok" from mmu
-	//function returns true if "ok" was received
-	//if timeout is set to true function return false if there is no "ok" received before timeout
-	bool response = true;
-	LongTimer mmu_get_reponse_timeout;
-	KEEPALIVE_STATE(IN_PROCESS);
-	mmu_get_reponse_timeout.start();
-	while (mmu_rx_ok() <= 0)
-	{
-		delay_keep_alive(100);
-		if (timeout && mmu_get_reponse_timeout.expired(5 * 60 * 1000ul))
-		{ //5 minutes timeout
-			response = false;
-			break;
-		}
-	}
-	printf_P(PSTR("mmu_get_response - end %d\n"), response?1:0);
-	return response;*/
 }
 
+//! @brief Wait for active extruder to reach temperature set
+//!
+//! This function is blocking and showing lcd_wait_for_heater() screen
+//! which is constantly updated with nozzle temperature.
+void mmu_wait_for_heater_blocking()
+{
+    while ((degTargetHotend(active_extruder) - degHotend(active_extruder)) > 5)
+    {
+        delay_keep_alive(1000);
+        lcd_wait_for_heater();
+    }
+}
 
 void manage_response(bool move_axes, bool turn_off_nozzle, uint8_t move)
 {
@@ -633,11 +666,7 @@ void manage_response(bool move_axes, bool turn_off_nozzle, uint8_t move)
 					lcd_display_message_fullscreen_P(_i("MMU OK. Resuming temperature..."));
 					delay_keep_alive(3000);
 				}
-				while ((degTargetHotend(active_extruder) - degHotend(active_extruder)) > 5) 
-				{
-					delay_keep_alive(1000);
-					lcd_wait_for_heater();
-				}
+                mmu_wait_for_heater_blocking();
 			  }			  
 			  if (move_axes) {
 				  lcd_clear();
@@ -751,7 +780,7 @@ void mmu_M600_load_filament(bool automatic)
 #endif //MMU_M600_SWITCH_EXTRUDER
 		  }
 		  else {
-			  tmp_extruder = (tmp_extruder+1)%5;
+			  tmp_extruder = ad_getAlternative(tmp_extruder);
 		  }
 		  lcd_update_enable(false);
 		  lcd_clear();
@@ -940,7 +969,7 @@ static const E_step ramming_sequence[] PROGMEM =
 };
 
 //! @brief Unload sequence to optimize shape of the tip of the unloaded filament
-static void filament_ramming()
+void mmu_filament_ramming()
 {
     for(uint8_t i = 0; i < (sizeof(ramming_sequence)/sizeof(E_step));++i)
     {
@@ -972,7 +1001,7 @@ void extr_unload()
 		if (mmu_extruder == MMU_FILAMENT_UNKNOWN) lcd_print(" ");
 		else lcd_print(mmu_extruder + 1);
 
-		filament_ramming();
+		mmu_filament_ramming();
 
 		mmu_command(MMU_CMD_U0);
 		// get response
@@ -1366,6 +1395,7 @@ void mmu_continue_loading()
 			setAllTargetHotends(0);
 			lcd_setstatuspgm(_i("MMU load failed     "));////MSG_RECOVERING_PRINT c=20 r=1
 			mmu_fil_loaded = false; //so we can retry same T-code again
+			isPrintPaused = true;
 		}
 	}
 	else { //mmu_ir_sensor_detected == false

+ 10 - 2
Firmware/mmu.h

@@ -1,4 +1,7 @@
-//mmu.h
+//! @file
+
+#ifndef MMU_H
+#define MMU_H
 
 #include <inttypes.h>
 
@@ -71,7 +74,7 @@ extern void mmu_command(uint8_t cmd);
 
 extern bool mmu_get_response(uint8_t move = 0);
 
-extern void manage_response(bool move_axes, bool turn_off_nozzle, uint8_t move = 0);
+extern void manage_response(bool move_axes, bool turn_off_nozzle, uint8_t move = MMU_NO_MOVE);
 
 extern void mmu_load_to_nozzle();
 
@@ -119,3 +122,8 @@ extern void mmu_eject_fil_2();
 extern void mmu_eject_fil_3();
 extern void mmu_eject_fil_4();
 extern void mmu_continue_loading();
+extern void mmu_filament_ramming();
+extern void mmu_wait_for_heater_blocking();
+extern void mmu_load_step(bool synchronize = true);
+
+#endif //MMU_H

+ 126 - 72
Firmware/temperature.cpp

@@ -41,6 +41,15 @@
 #include "adc.h"
 #include "ConfigurationStore.h"
 
+#include "Timer.h"
+#include "Configuration_prusa.h"
+
+
+extern "C" {
+extern void timer02_init(void);
+extern void timer02_set_pwm0(uint8_t pwm0);
+}
+
 
 //===========================================================================
 //=============================public variables============================
@@ -103,15 +112,15 @@ static volatile bool temp_meas_ready = false;
 
 #ifdef PIDTEMP
   //static cannot be external:
-  static float temp_iState[EXTRUDERS] = { 0 };
-  static float temp_dState[EXTRUDERS] = { 0 };
+  static float iState_sum[EXTRUDERS] = { 0 };
+  static float dState_last[EXTRUDERS] = { 0 };
   static float pTerm[EXTRUDERS];
   static float iTerm[EXTRUDERS];
   static float dTerm[EXTRUDERS];
   //int output;
   static float pid_error[EXTRUDERS];
-  static float temp_iState_min[EXTRUDERS];
-  static float temp_iState_max[EXTRUDERS];
+  static float iState_sum_min[EXTRUDERS];
+  static float iState_sum_max[EXTRUDERS];
   // static float pid_input[EXTRUDERS];
   // static float pid_output[EXTRUDERS];
   static bool pid_reset[EXTRUDERS];
@@ -152,6 +161,8 @@ static volatile bool temp_meas_ready = false;
   # define ARRAY_BY_EXTRUDERS(v1, v2, v3) { v1 }
 #endif
 
+static ShortTimer oTimer4minTempHeater,oTimer4minTempBed;
+
 // Init min and max temp with extreme values to prevent false errors during startup
 static int minttemp_raw[EXTRUDERS] = ARRAY_BY_EXTRUDERS( HEATER_0_RAW_LO_TEMP , HEATER_1_RAW_LO_TEMP , HEATER_2_RAW_LO_TEMP );
 static int maxttemp_raw[EXTRUDERS] = ARRAY_BY_EXTRUDERS( HEATER_0_RAW_HI_TEMP , HEATER_1_RAW_HI_TEMP , HEATER_2_RAW_HI_TEMP );
@@ -252,6 +263,7 @@ static void temp_runaway_stop(bool isPreheat, bool isBed);
   if (extruder<0)
   {
      soft_pwm_bed = (MAX_BED_POWER)/2;
+	 timer02_set_pwm0(soft_pwm_bed << 1);
      bias = d = (MAX_BED_POWER)/2;
    }
    else
@@ -288,7 +300,10 @@ static void temp_runaway_stop(bool isPreheat, bool isBed);
         if(millis() - t2 > 5000) { 
           heating=false;
           if (extruder<0)
+		  {
             soft_pwm_bed = (bias - d) >> 1;
+			timer02_set_pwm0(soft_pwm_bed << 1);
+		  }
           else
             soft_pwm[extruder] = (bias - d) >> 1;
           t1=millis();
@@ -342,7 +357,10 @@ static void temp_runaway_stop(bool isPreheat, bool isBed);
             }
           }
           if (extruder<0)
+		  {
             soft_pwm_bed = (bias + d) >> 1;
+			timer02_set_pwm0(soft_pwm_bed << 1);
+		  }
           else
             soft_pwm[extruder] = (bias + d) >> 1;
           pid_cycle++;
@@ -413,7 +431,7 @@ void updatePID()
 {
 #ifdef PIDTEMP
   for(int e = 0; e < EXTRUDERS; e++) { 
-     temp_iState_max[e] = PID_INTEGRAL_DRIVE_MAX / cs.Ki;  
+     iState_sum_max[e] = PID_INTEGRAL_DRIVE_MAX / cs.Ki;  
   }
 #endif
 #ifdef PIDTEMPBED
@@ -582,6 +600,12 @@ void checkExtruderAutoFans()
 
 #endif // any extruder auto fan pins set
 
+// ready for eventually parameters adjusting
+void resetPID(uint8_t)                            // only for compiler-warning elimination (if function do nothing)
+//void resetPID(uint8_t extruder)
+{
+}
+
 void manage_heater()
 {
 #ifdef WATCHDOG
@@ -593,9 +617,13 @@ void manage_heater()
 
   if(temp_meas_ready != true)   //better readability
     return; 
+// more precisely - this condition partially stabilizes time interval for regulation values evaluation (@ ~ 230ms)
 
   updateTemperaturesFromRawValues();
 
+  check_max_temp();
+  check_min_temp();
+
 #ifdef TEMP_RUNAWAY_BED_HYSTERESIS
   temp_runaway_check(0, target_temperature_bed, current_temperature_bed, (int)soft_pwm_bed, true);
 #endif
@@ -611,38 +639,42 @@ void manage_heater()
     pid_input = current_temperature[e];
 
     #ifndef PID_OPENLOOP
-        pid_error[e] = target_temperature[e] - pid_input;
-        if(pid_error[e] > PID_FUNCTIONAL_RANGE) {
-          pid_output = BANG_MAX;
-          pid_reset[e] = true;
-        }
-        else if(pid_error[e] < -PID_FUNCTIONAL_RANGE || target_temperature[e] == 0) {
+        if(target_temperature[e] == 0) {
           pid_output = 0;
           pid_reset[e] = true;
-        }
-        else {
-          if(pid_reset[e] == true) {
-            temp_iState[e] = 0.0;
+        } else {
+          pid_error[e] = target_temperature[e] - pid_input;
+          if(pid_reset[e]) {
+            iState_sum[e] = 0.0;
+            dTerm[e] = 0.0;                       // 'dState_last[e]' initial setting is not necessary (see end of if-statement)
             pid_reset[e] = false;
           }
+#ifndef PonM
           pTerm[e] = cs.Kp * pid_error[e];
-          temp_iState[e] += pid_error[e];
-          temp_iState[e] = constrain(temp_iState[e], temp_iState_min[e], temp_iState_max[e]);
-          iTerm[e] = cs.Ki * temp_iState[e];
-
-          //K1 defined in Configuration.h in the PID settings
+          iState_sum[e] += pid_error[e];
+          iState_sum[e] = constrain(iState_sum[e], iState_sum_min[e], iState_sum_max[e]);
+          iTerm[e] = cs.Ki * iState_sum[e];
+          // K1 defined in Configuration.h in the PID settings
           #define K2 (1.0-K1)
-          dTerm[e] = (cs.Kd * (pid_input - temp_dState[e]))*K2 + (K1 * dTerm[e]);
-          pid_output = pTerm[e] + iTerm[e] - dTerm[e];
+          dTerm[e] = (cs.Kd * (pid_input - dState_last[e]))*K2 + (K1 * dTerm[e]); // e.g. digital filtration of derivative term changes
+          pid_output = pTerm[e] + iTerm[e] - dTerm[e]; // subtraction due to "Derivative on Measurement" method (i.e. derivative of input instead derivative of error is used)
           if (pid_output > PID_MAX) {
-            if (pid_error[e] > 0 )  temp_iState[e] -= pid_error[e]; // conditional un-integration
+            if (pid_error[e] > 0 ) iState_sum[e] -= pid_error[e]; // conditional un-integration
             pid_output=PID_MAX;
-          } else if (pid_output < 0){
-            if (pid_error[e] < 0 )  temp_iState[e] -= pid_error[e]; // conditional un-integration
+          } else if (pid_output < 0) {
+            if (pid_error[e] < 0 ) iState_sum[e] -= pid_error[e]; // conditional un-integration
             pid_output=0;
           }
+#else // PonM ("Proportional on Measurement" method)
+          iState_sum[e] += cs.Ki * pid_error[e];
+          iState_sum[e] -= cs.Kp * (pid_input - dState_last[e]);
+          iState_sum[e] = constrain(iState_sum[e], 0, PID_INTEGRAL_DRIVE_MAX);
+          dTerm[e] = cs.Kd * (pid_input - dState_last[e]);
+          pid_output = iState_sum[e] - dTerm[e];  // subtraction due to "Derivative on Measurement" method (i.e. derivative of input instead derivative of error is used)
+          pid_output = constrain(pid_output, 0, PID_MAX);
+#endif // PonM
         }
-        temp_dState[e] = pid_input;
+        dState_last[e] = pid_input;
     #else 
           pid_output = constrain(target_temperature[e], 0, PID_MAX);
     #endif //PID_OPENLOOP
@@ -659,7 +691,7 @@ void manage_heater()
     SERIAL_ECHO(" iTerm ");
     SERIAL_ECHO(iTerm[e]);
     SERIAL_ECHO(" dTerm ");
-    SERIAL_ECHOLN(dTerm[e]);
+    SERIAL_ECHOLN(-dTerm[e]);
     #endif //PID_DEBUG
   #else /* PID off */
     pid_output = 0;
@@ -669,16 +701,12 @@ void manage_heater()
   #endif
 
     // Check if temperature is within the correct range
-#ifdef AMBIENT_THERMISTOR
-    if(((current_temperature_ambient < MINTEMP_MINAMBIENT) || (current_temperature[e] > minttemp[e])) && (current_temperature[e] < maxttemp[e])) 
-#else //AMBIENT_THERMISTOR
-    if((current_temperature[e] > minttemp[e]) && (current_temperature[e] < maxttemp[e])) 
-#endif //AMBIENT_THERMISTOR
+    if((current_temperature[e] < maxttemp[e]) && (target_temperature[e] != 0))
     {
       soft_pwm[e] = (int)pid_output >> 1;
     }
     else
-	{
+    {
       soft_pwm[e] = 0;
     }
 
@@ -763,55 +791,61 @@ void manage_heater()
       pid_output = constrain(target_temperature_bed, 0, MAX_BED_POWER);
     #endif //PID_OPENLOOP
 
-#ifdef AMBIENT_THERMISTOR
-	  if(((current_temperature_bed > BED_MINTEMP) || (current_temperature_ambient < MINTEMP_MINAMBIENT)) && (current_temperature_bed < BED_MAXTEMP)) 
-#else //AMBIENT_THERMISTOR
-	  if((current_temperature_bed > BED_MINTEMP) && (current_temperature_bed < BED_MAXTEMP)) 
-#endif //AMBIENT_THERMISTOR
+	  if(current_temperature_bed < BED_MAXTEMP)
 	  {
 	    soft_pwm_bed = (int)pid_output >> 1;
+		timer02_set_pwm0(soft_pwm_bed << 1);
 	  }
 	  else {
 	    soft_pwm_bed = 0;
+		timer02_set_pwm0(soft_pwm_bed << 1);
 	  }
 
     #elif !defined(BED_LIMIT_SWITCHING)
       // Check if temperature is within the correct range
-      if((current_temperature_bed > BED_MINTEMP) && (current_temperature_bed < BED_MAXTEMP))
+      if(current_temperature_bed < BED_MAXTEMP)
       {
         if(current_temperature_bed >= target_temperature_bed)
         {
           soft_pwm_bed = 0;
+		  timer02_set_pwm0(soft_pwm_bed << 1);
         }
         else 
         {
           soft_pwm_bed = MAX_BED_POWER>>1;
+		  timer02_set_pwm0(soft_pwm_bed << 1);
         }
       }
       else
       {
         soft_pwm_bed = 0;
+		timer02_set_pwm0(soft_pwm_bed << 1);
         WRITE(HEATER_BED_PIN,LOW);
       }
     #else //#ifdef BED_LIMIT_SWITCHING
       // Check if temperature is within the correct band
-      if((current_temperature_bed > BED_MINTEMP) && (current_temperature_bed < BED_MAXTEMP))
+      if(current_temperature_bed < BED_MAXTEMP)
       {
         if(current_temperature_bed > target_temperature_bed + BED_HYSTERESIS)
         {
           soft_pwm_bed = 0;
+		  timer02_set_pwm0(soft_pwm_bed << 1);
         }
         else if(current_temperature_bed <= target_temperature_bed - BED_HYSTERESIS)
         {
           soft_pwm_bed = MAX_BED_POWER>>1;
+          timer02_set_pwm0(soft_pwm_bed << 1);
         }
       }
       else
       {
         soft_pwm_bed = 0;
+		timer02_set_pwm0(soft_pwm_bed << 1);
         WRITE(HEATER_BED_PIN,LOW);
       }
     #endif
+      if(target_temperature_bed==0)
+        soft_pwm_bed = 0;
   #endif
   
 #ifdef HOST_KEEPALIVE_FEATURE
@@ -983,7 +1017,6 @@ static void updateTemperaturesFromRawValues()
     CRITICAL_SECTION_END;
 }
 
-
 void tp_init()
 {
 #if MB(RUMBA) && ((TEMP_SENSOR_0==-1)||(TEMP_SENSOR_1==-1)||(TEMP_SENSOR_2==-1)||(TEMP_SENSOR_BED==-1))
@@ -997,8 +1030,8 @@ void tp_init()
     // populate with the first value 
     maxttemp[e] = maxttemp[0];
 #ifdef PIDTEMP
-    temp_iState_min[e] = 0.0;
-    temp_iState_max[e] = PID_INTEGRAL_DRIVE_MAX / cs.Ki;
+    iState_sum_min[e] = 0.0;
+    iState_sum_max[e] = PID_INTEGRAL_DRIVE_MAX / cs.Ki;
 #endif //PIDTEMP
 #ifdef PIDTEMPBED
     temp_iState_min_bed = 0.0;
@@ -1050,10 +1083,12 @@ void tp_init()
 
   adc_init();
 
+  timer02_init();
+
   // Use timer0 for temperature measurement
   // Interleave temperature interrupt with millies interrupt
-  OCR0B = 128;
-  TIMSK0 |= (1<<OCIE0B);  
+  OCR2B = 128;
+  TIMSK2 |= (1<<OCIE2B);  
   
   // Wait for temperature measurement to settle
   delay(250);
@@ -1361,6 +1396,7 @@ void disable_heater()
   #if defined(TEMP_BED_PIN) && TEMP_BED_PIN > -1
     target_temperature_bed=0;
     soft_pwm_bed=0;
+	timer02_set_pwm0(soft_pwm_bed << 1);
     #if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1  
       WRITE(HEATER_BED_PIN,LOW);
     #endif
@@ -1525,8 +1561,8 @@ void adc_ready(void) //callback from adc when sampling finished
 } // extern "C"
 
 
-// Timer 0 is shared with millies
-ISR(TIMER0_COMPB_vect)
+// Timer2 (originaly timer0) is shared with millies
+ISR(TIMER2_COMPB_vect)
 {
 	static bool _lock = false;
 	if (_lock) return;
@@ -1534,11 +1570,6 @@ ISR(TIMER0_COMPB_vect)
 	asm("sei");
 
 	if (!temp_meas_ready) adc_cycle();
-	else
-	{
-		check_max_temp();
-		check_min_temp();
-	}
 	lcd_buttons_update();
 
   static unsigned char pwm_count = (1 << SOFT_PWM_SCALE);
@@ -1598,7 +1629,7 @@ ISR(TIMER0_COMPB_vect)
 #endif
 #if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1
     soft_pwm_b = soft_pwm_bed;
-    if(soft_pwm_b > 0) WRITE(HEATER_BED_PIN,1); else WRITE(HEATER_BED_PIN,0);
+    //if(soft_pwm_b > 0) WRITE(HEATER_BED_PIN,1); else WRITE(HEATER_BED_PIN,0);
 #endif
   }
 #ifdef FAN_SOFT_PWM
@@ -1735,7 +1766,7 @@ ISR(TIMER0_COMPB_vect)
 	  state_timer_heater_b = MIN_STATE_TIME;
 	}
 	state_heater_b = 1;
-	WRITE(HEATER_BED_PIN, 1);
+	//WRITE(HEATER_BED_PIN, 1);
       }
     } else {
       // turn OFF heather only if the minimum time is up 
@@ -1934,26 +1965,49 @@ void check_min_temp_bed()
 
 void check_min_temp()
 {
+static bool bCheckingOnHeater=false;              // state variable, which allows to short no-checking delay (is set, when temperature is (first time) over heaterMintemp)
+static bool bCheckingOnBed=false;                 // state variable, which allows to short no-checking delay (is set, when temperature is (first time) over bedMintemp)
 #ifdef AMBIENT_THERMISTOR
-	static uint8_t heat_cycles = 0;
-	if (current_temperature_raw_ambient > OVERSAMPLENR*MINTEMP_MINAMBIENT_RAW)
-	{
-		if (READ(HEATER_0_PIN) == HIGH)
-		{
-//			if ((heat_cycles % 10) == 0)
-//				printf_P(PSTR("X%d\n"), heat_cycles);
-			if (heat_cycles > 50) //reaction time 5-10s
-				check_min_temp_heater0();
-			else
-				heat_cycles++;
-		}
-		else
-			heat_cycles = 0;
-		return;
-	}
+if(current_temperature_raw_ambient>(OVERSAMPLENR*MINTEMP_MINAMBIENT_RAW)) // thermistor is NTC type, so operator is ">" ;-)
+     {                                            // ambient temperature is low
+#endif //AMBIENT_THERMISTOR
+// *** 'common' part of code for MK2.5 & MK3
+// * nozzle checking
+if(target_temperature[active_extruder]>minttemp[active_extruder])
+     {                                            // ~ nozzle heating is on
+     bCheckingOnHeater=bCheckingOnHeater||(current_temperature[active_extruder]>=minttemp[active_extruder]); // for eventually delay cutting
+     if(oTimer4minTempHeater.expired(HEATER_MINTEMP_DELAY)||(!oTimer4minTempHeater.running())||bCheckingOnHeater)
+          {
+          bCheckingOnHeater=true;                 // not necessary
+		check_min_temp_heater0();               // delay is elapsed or temperature is/was over minTemp => periodical checking is active
+          }
+     }
+else {                                            // ~ nozzle heating is off
+     oTimer4minTempHeater.start();
+     bCheckingOnHeater=false;
+     }
+// * bed checking
+if(target_temperature_bed>BED_MINTEMP)
+     {                                            // ~ bed heating is on
+     bCheckingOnBed=bCheckingOnBed||(current_temperature_bed>=BED_MINTEMP); // for eventually delay cutting
+     if(oTimer4minTempBed.expired(BED_MINTEMP_DELAY)||(!oTimer4minTempBed.running())||bCheckingOnBed)
+          {
+          bCheckingOnBed=true;                    // not necessary
+		check_min_temp_bed();                   // delay is elapsed or temperature is/was over minTemp => periodical checking is active
+          }
+     }
+else {                                            // ~ bed heating is off
+     oTimer4minTempBed.start();
+     bCheckingOnBed=false;
+     }
+// *** end of 'common' part
+#ifdef AMBIENT_THERMISTOR
+     }
+else {                                            // ambient temperature is standard
+     check_min_temp_heater0();
+     check_min_temp_bed();
+     }
 #endif //AMBIENT_THERMISTOR
-	check_min_temp_heater0();
-	check_min_temp_bed();
 }
  
 #if (defined(FANCHECK) && defined(TACH_0) && (TACH_0 > -1))

+ 9 - 3
Firmware/temperature.h

@@ -27,8 +27,8 @@
   #include "stepper.h"
 #endif
 
-#define ENABLE_TEMPERATURE_INTERRUPT()  TIMSK0 |= (1<<OCIE0B)
-#define DISABLE_TEMPERATURE_INTERRUPT() TIMSK0 &= ~(1<<OCIE0B)
+#define ENABLE_TEMPERATURE_INTERRUPT()  TIMSK2 |= (1<<OCIE2B)
+#define DISABLE_TEMPERATURE_INTERRUPT() TIMSK2 &= ~(1<<OCIE2B)
 
 // public functions
 void tp_init();  //initialize the heating
@@ -87,6 +87,8 @@ extern int current_voltage_raw_bed;
   extern volatile int babystepsTodo[3];
 #endif
 
+void resetPID(uint8_t extruder);
+
 inline void babystepsTodoZadd(int n)
 {
     if (n != 0) {
@@ -137,11 +139,15 @@ FORCE_INLINE float degTargetBed() {
 
 FORCE_INLINE void setTargetHotend(const float &celsius, uint8_t extruder) {  
   target_temperature[extruder] = celsius;
+  resetPID(extruder);
 };
 
 static inline void setTargetHotendSafe(const float &celsius, uint8_t extruder)
 {
-    if (extruder<EXTRUDERS) target_temperature[extruder] = celsius;
+    if (extruder<EXTRUDERS) {
+      target_temperature[extruder] = celsius;
+      resetPID(extruder);
+    }
 }
 
 static inline void setAllTargetHotends(const float &celsius)

+ 103 - 0
Firmware/timer02.c

@@ -0,0 +1,103 @@
+//timer02.c
+// use atmega timer2 as main system timer instead of timer0
+// timer0 is used for fast pwm (OC0B output)
+// original OVF handler is disabled
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <Arduino.h>
+
+
+uint8_t timer02_pwm0 = 0;
+
+void timer02_set_pwm0(uint8_t pwm0)
+{
+	if (timer02_pwm0 == pwm0) return;
+	if (pwm0)
+	{
+		TCCR0A |= (2 << COM0B0);
+		OCR0B = pwm0 - 1;
+	}
+	else
+	{
+		TCCR0A &= ~(2 << COM0B0);
+		OCR0B = 0;
+	}
+}
+
+void timer02_init(void)
+{
+	//save sreg
+	uint8_t _sreg = SREG;
+	//disable interrupts for sure
+	cli();
+	//mask timer0 interrupts - disable all
+	TIMSK0 &= ~(1<<TOIE0);
+	TIMSK0 &= ~(1<<OCIE0A);
+	TIMSK0 &= ~(1<<OCIE0B);
+	//setup timer0
+	TCCR0A = 0x00; //COM_A-B=00, WGM_0-1=00
+	TCCR0B = (1 << CS00); //WGM_2=0, CS_0-2=011
+	//switch timer0 to fast pwm mode
+	TCCR0A |= (3 << WGM00); //WGM_0-1=11
+	//set OCR0B register to zero
+	OCR0B = 0;
+	//disable OCR0B output (will be enabled in timer02_set_pwm0)
+	TCCR0A &= ~(2 << COM0B0);
+	//setup timer2
+	TCCR2A = 0x00; //COM_A-B=00, WGM_0-1=00
+	TCCR2B = (3 << CS20); //WGM_2=0, CS_0-2=011
+	//mask timer2 interrupts - enable OVF, disable others
+	TIMSK2 |= (1<<TOIE2);
+	TIMSK2 &= ~(1<<OCIE2A);
+	TIMSK2 &= ~(1<<OCIE2B);
+	//set timer2 OCR registers (OCRB interrupt generated 0.5ms after OVF interrupt)
+	OCR2A = 0;
+	OCR2B = 128;
+	//restore sreg (enable interrupts)
+	SREG = _sreg;
+}
+
+
+//following code is OVF handler for timer 2
+//it is copy-paste from wiring.c and modified for timer2
+//variables timer0_overflow_count and timer0_millis are declared in wiring.c
+
+
+
+// the prescaler is set so that timer0 ticks every 64 clock cycles, and the
+// the overflow handler is called every 256 ticks.
+#define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256))
+
+// the whole number of milliseconds per timer0 overflow
+#define MILLIS_INC (MICROSECONDS_PER_TIMER0_OVERFLOW / 1000)
+
+// the fractional number of milliseconds per timer0 overflow. we shift right
+// by three to fit these numbers into a byte. (for the clock speeds we care
+// about - 8 and 16 MHz - this doesn't lose precision.)
+#define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3)
+#define FRACT_MAX (1000 >> 3)
+
+extern volatile unsigned long timer0_overflow_count;
+extern volatile unsigned long timer0_millis;
+unsigned char timer0_fract = 0;
+
+ISR(TIMER2_OVF_vect)
+{
+	// copy these to local variables so they can be stored in registers
+	// (volatile variables must be read from memory on every access)
+	unsigned long m = timer0_millis;
+	unsigned char f = timer0_fract;
+
+	m += MILLIS_INC;
+	f += FRACT_INC;
+	if (f >= FRACT_MAX)
+	{
+		f -= FRACT_MAX;
+		m += 1;
+	}
+
+	timer0_fract = f;
+	timer0_millis = m;
+	timer0_overflow_count++;
+}
+

+ 141 - 46
Firmware/ultralcd.cpp

@@ -163,6 +163,7 @@ static void lcd_selftest_screen_step(int _row, int _col, int _state, const char
 static bool lcd_selftest_manual_fan_check(int _fan, bool check_opposite);
 static bool lcd_selftest_fan_dialog(int _fan);
 static bool lcd_selftest_fsensor();
+static bool selftest_irsensor();
 static void lcd_selftest_error(int _error_no, const char *_error_1, const char *_error_2);
 static void lcd_colorprint_change();
 #ifdef SNMM
@@ -237,6 +238,8 @@ bool wait_for_unclick;
 // float raw_Ki, raw_Kd;
 #endif
 
+bool bMain;                                       // flag (i.e. 'fake parameter') for 'lcd_sdcard_menu()' function
+
 
 
 const char STR_SEPARATOR[] PROGMEM = "------------";
@@ -5886,7 +5889,10 @@ static void lcd_main_menu()
 		if (!is_usb_printing && (lcd_commands_type != LCD_COMMAND_V2_CAL))
 		{
 			//if (farm_mode) MENU_ITEM_SUBMENU_P(MSG_FARM_CARD_MENU, lcd_farm_sdcard_menu);
-			/*else*/ MENU_ITEM_SUBMENU_P(_T(MSG_CARD_MENU), lcd_sdcard_menu);
+			/*else*/ {
+                        bMain=true;               // flag ('fake parameter') for 'lcd_sdcard_menu()' function
+                        MENU_ITEM_SUBMENU_P(_T(MSG_CARD_MENU), lcd_sdcard_menu);
+                        }
 		}
 #if SDCARDDETECT < 1
       MENU_ITEM_GCODE_P(_i("Change SD card"), PSTR("M21"));  // SD-card changed by user////MSG_CNG_SDCARD c=0 r=0
@@ -5895,6 +5901,7 @@ static void lcd_main_menu()
 	
   } else 
   {
+    bMain=true;                                   // flag (i.e. 'fake parameter') for 'lcd_sdcard_menu()' function
     MENU_ITEM_SUBMENU_P(_i("No SD card"), lcd_sdcard_menu);////MSG_NO_CARD c=0 r=0
 #if SDCARDDETECT < 1
     MENU_ITEM_GCODE_P(_i("Init. SD card"), PSTR("M21")); // Manually initialize the SD-card via user interface////MSG_INIT_SDCARD c=0 r=0
@@ -6227,7 +6234,10 @@ void lcd_sdcard_menu()
 
 
   MENU_BEGIN();
-  MENU_ITEM_BACK_P(_T(MSG_MAIN));
+  if(bMain)                                       // i.e. default menu-item
+    MENU_ITEM_BACK_P(_T(MSG_MAIN));
+  else                                            // i.e. menu-item after card insertion
+    MENU_ITEM_FUNCTION_P(_T(MSG_WATCH),lcd_return_to_status);
   card.getWorkDirName();
   if (card.filename[0] == '/')
   {
@@ -6323,28 +6333,24 @@ bool lcd_selftest()
 		_result = true;
 #endif
 	}
-	
-	if (_result)
-	{
-		_progress = lcd_selftest_screen(3, _progress, 3, true, 1000);
-		_result = lcd_selfcheck_check_heater(false);
-	}
-
 
 	if (_result)
 	{
 		//current_position[Z_AXIS] += 15;									//move Z axis higher to avoid false triggering of Z end stop in case that we are very low - just above heatbed
-		_progress = lcd_selftest_screen(4, _progress, 3, true, 2000);
+		_progress = lcd_selftest_screen(3, _progress, 3, true, 2000);
 #ifdef TMC2130
-		_result = lcd_selfcheck_axis_sg(X_AXIS);
+        _result = lcd_selfcheck_axis_sg(X_AXIS);
 #else
-		_result = lcd_selfcheck_axis(X_AXIS, X_MAX_POS);
+        _result = lcd_selfcheck_axis(X_AXIS, X_MAX_POS);
 #endif //TMC2130
 	}
 
+
+
+
 	if (_result)
 	{
-		_progress = lcd_selftest_screen(4, _progress, 3, true, 0);
+		_progress = lcd_selftest_screen(3, _progress, 3, true, 0);
 
 #ifndef TMC2130
 		_result = lcd_selfcheck_pulleys(X_AXIS);
@@ -6354,7 +6360,7 @@ bool lcd_selftest()
 
 	if (_result)
 	{
-		_progress = lcd_selftest_screen(5, _progress, 3, true, 1500);
+		_progress = lcd_selftest_screen(4, _progress, 3, true, 1500);
 #ifdef TMC2130
 		_result = lcd_selfcheck_axis_sg(Y_AXIS);
 #else
@@ -6364,7 +6370,7 @@ bool lcd_selftest()
 
 	if (_result)
 	{
-		_progress = lcd_selftest_screen(5, _progress, 3, true, 0);
+		_progress = lcd_selftest_screen(4, _progress, 3, true, 0);
 #ifndef TMC2130
 		_result = lcd_selfcheck_pulleys(Y_AXIS);
 #endif // TMC2130
@@ -6385,7 +6391,7 @@ bool lcd_selftest()
 		current_position[Z_AXIS] = current_position[Z_AXIS] + 10;
 		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder);
 		st_synchronize();
-		_progress = lcd_selftest_screen(6, _progress, 3, true, 1500);
+		_progress = lcd_selftest_screen(5, _progress, 3, true, 1500);
 		_result = lcd_selfcheck_axis(2, Z_MAX_POS);
 		if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE) != 1) {
 			enquecommand_P(PSTR("G28 W"));
@@ -6412,25 +6418,46 @@ bool lcd_selftest()
 
 	if (_result)
 	{
-		_progress = lcd_selftest_screen(7, _progress, 3, true, 2000); //check bed
+		_progress = lcd_selftest_screen(6, _progress, 3, true, 2000); //check bed
 		_result = lcd_selfcheck_check_heater(true);
 	}
+
+    if (_result)
+    {
+        _progress = lcd_selftest_screen(7, _progress, 3, true, 1000); //check nozzle
+        _result = lcd_selfcheck_check_heater(false);
+    }
 	if (_result)
 	{
-		_progress = lcd_selftest_screen(8, _progress, 3, true, 2000); //bed ok
+		_progress = lcd_selftest_screen(8, _progress, 3, true, 2000); //nozzle ok
+	}
+#ifdef FILAMENT_SENSOR
+    if (_result)
+    {
+
+        if (mmu_enabled)
+        {        
+			_progress = lcd_selftest_screen(9, _progress, 3, true, 2000); //check filaments sensor
+            _result = selftest_irsensor();
+		    if (_result)
+			{
+				_progress = lcd_selftest_screen(10, _progress, 3, true, 2000); //fil sensor OK
+			}
+        } else
+        {
 #ifdef PAT9125
-		if (mmu_enabled == false) {
 			_progress = lcd_selftest_screen(9, _progress, 3, true, 2000); //check filaments sensor
-			_result = lcd_selftest_fsensor();
-		}
-	}
+            _result = lcd_selftest_fsensor();
+			if (_result)
+			{
+				_progress = lcd_selftest_screen(10, _progress, 3, true, 2000); //fil sensor OK
+			}
+#endif //PAT9125
+        }
+    }
+#endif //FILAMENT_SENSOR
 	if (_result)
 	{
-		if (mmu_enabled == false)
-		{
-			_progress = lcd_selftest_screen(10, _progress, 3, true, 2000); //fil sensor OK
-		}
-#endif // PAT9125
 		_progress = lcd_selftest_screen(11, _progress, 3, true, 5000); //all correct
 	}
 	else
@@ -6642,7 +6669,7 @@ static bool lcd_selfcheck_axis(int _axis, int _travel)
 		}
 		else
 		{
-			_progress = lcd_selftest_screen(4 + _axis, _progress, 3, false, 0);
+			_progress = lcd_selftest_screen(3 + _axis, _progress, 3, false, 0);
 			_lcd_refresh = 0;
 		}
 
@@ -6809,7 +6836,7 @@ static bool lcd_selfcheck_check_heater(bool _isbed)
 
 		manage_heater();
 		manage_inactivity(true);
-		_progress = (_isbed) ? lcd_selftest_screen(7, _progress, 2, false, 400) : lcd_selftest_screen(3, _progress, 2, false, 400);
+		_progress = (_isbed) ? lcd_selftest_screen(6, _progress, 2, false, 400) : lcd_selftest_screen(7, _progress, 2, false, 400);
 		/*if (_isbed) {
 			MYSERIAL.print("Bed temp:");
 			MYSERIAL.println(degBed());
@@ -6835,9 +6862,10 @@ static bool lcd_selfcheck_check_heater(bool _isbed)
 	MYSERIAL.print("Opposite result:");
 	MYSERIAL.println(_opposite_result);
 	*/
-	if (_opposite_result < ((_isbed) ? 10 : 3))
+
+	if (_opposite_result < ((_isbed) ? 30 : 9))
 	{
-		if (_checked_result >= ((_isbed) ? 3 : 10))
+		if (_checked_result >= ((_isbed) ? 9 : 30))
 		{
 			_stepresult = true;
 		}
@@ -6985,6 +7013,70 @@ static bool lcd_selftest_fsensor(void)
 	}
 	return (!fsensor_not_responding);
 }
+
+//! @brief Self-test of infrared barrier filament sensor mounted on MK3S with MMUv2 printer
+//!
+//! Test whether sensor is not triggering filament presence when extruder idler is moving without filament.
+//!
+//! Steps:
+//!  * Backup current active extruder temperature
+//!  * Pre-heat to PLA extrude temperature.
+//!  * Unload filament possibly present.
+//!  * Move extruder idler same way as during filament load
+//!    and sample MMU_IDLER_SENSOR_PIN.
+//!  * Check that pin doesn't go low.
+//!
+//! @retval true passed
+//! @retval false failed
+static bool selftest_irsensor()
+{
+    class TempBackup
+    {
+    public:
+        TempBackup():
+            m_temp(degTargetHotend(active_extruder)),
+            m_extruder(active_extruder){}
+        ~TempBackup(){setTargetHotend(m_temp,m_extruder);}
+    private:
+        float m_temp;
+        uint8_t m_extruder;
+    };
+    uint8_t progress;
+    {
+        TempBackup tempBackup;
+        setTargetHotend(ABS_PREHEAT_HOTEND_TEMP,active_extruder);
+        mmu_wait_for_heater_blocking();
+        progress = lcd_selftest_screen(9, 0, 1, true, 0);
+        mmu_filament_ramming();
+    }
+    progress = lcd_selftest_screen(9, progress, 1, true, 0);
+    mmu_command(MMU_CMD_U0);
+    manage_response(false, false);
+
+    for(uint_least8_t i = 0; i < 200; ++i)
+    {
+        if (0 == (i % 32)) progress = lcd_selftest_screen(9, progress, 1, true, 0);
+
+        mmu_load_step(false);
+        while (blocks_queued())
+        {
+            if (PIN_GET(MMU_IDLER_SENSOR_PIN) == 0) return false;
+#ifdef TMC2130
+            manage_heater();
+            // Vojtech: Don't disable motors inside the planner!
+            if (!tmc2130_update_sg())
+            {
+                manage_inactivity(true);
+            }
+#else //TMC2130
+            manage_heater();
+            // Vojtech: Don't disable motors inside the planner!
+            manage_inactivity(true);
+#endif //TMC2130
+        }
+    }
+    return true;
+}
 #endif //FILAMENT_SENSOR
 
 static bool lcd_selftest_manual_fan_check(int _fan, bool check_opposite)
@@ -7147,7 +7239,7 @@ static int lcd_selftest_screen(int _step, int _progress, int _progress_scale, bo
     lcd_update_enable(false);
 
 	int _step_block = 0;
-	const char *_indicator = (_progress > _progress_scale) ? "-" : "|";
+	const char *_indicator = (_progress >= _progress_scale) ? "-" : "|";
 
 	if (_clear) lcd_clear();
 
@@ -7158,12 +7250,12 @@ static int lcd_selftest_screen(int _step, int _progress, int _progress_scale, bo
 	if (_step == 0) lcd_puts_P(_T(MSG_SELFTEST_FAN));
 	if (_step == 1) lcd_puts_P(_T(MSG_SELFTEST_FAN));
 	if (_step == 2) lcd_puts_P(_i("Checking endstops"));////MSG_SELFTEST_CHECK_ENDSTOPS c=20 r=0
-	if (_step == 3) lcd_puts_P(_i("Checking hotend  "));////MSG_SELFTEST_CHECK_HOTEND c=20 r=0
-	if (_step == 4) lcd_puts_P(_i("Checking X axis  "));////MSG_SELFTEST_CHECK_X c=20 r=0
-	if (_step == 5) lcd_puts_P(_i("Checking Y axis  "));////MSG_SELFTEST_CHECK_Y c=20 r=0
-	if (_step == 6) lcd_puts_P(_i("Checking Z axis  "));////MSG_SELFTEST_CHECK_Z c=20 r=0
-	if (_step == 7) lcd_puts_P(_T(MSG_SELFTEST_CHECK_BED));
-	if (_step == 8) lcd_puts_P(_T(MSG_SELFTEST_CHECK_BED));
+	if (_step == 3) lcd_puts_P(_i("Checking X axis  "));////MSG_SELFTEST_CHECK_X c=20 r=0
+	if (_step == 4) lcd_puts_P(_i("Checking Y axis  "));////MSG_SELFTEST_CHECK_Y c=20 r=0
+	if (_step == 5) lcd_puts_P(_i("Checking Z axis  "));////MSG_SELFTEST_CHECK_Z c=20 r=0
+	if (_step == 6) lcd_puts_P(_T(MSG_SELFTEST_CHECK_BED));
+	if (_step == 7
+	    || _step == 8) lcd_puts_P(_i("Checking hotend  "));////MSG_SELFTEST_CHECK_HOTEND c=20 r=0
 	if (_step == 9) lcd_puts_P(_T(MSG_SELFTEST_CHECK_FSENSOR));
 	if (_step == 10) lcd_puts_P(_T(MSG_SELFTEST_CHECK_FSENSOR));
 	if (_step == 11) lcd_puts_P(_i("All correct      "));////MSG_SELFTEST_CHECK_ALLCORRECT c=20 r=0
@@ -7191,26 +7283,27 @@ static int lcd_selftest_screen(int _step, int _progress, int _progress_scale, bo
 	else if (_step < 9)
 	{
 		//SERIAL_ECHOLNPGM("Other tests");
-		_step_block = 3;
-		lcd_selftest_screen_step(3, 9, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Hotend", _indicator);
 
-		_step_block = 4;
+		_step_block = 3;
 		lcd_selftest_screen_step(2, 2, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "X", _indicator);
 
-		_step_block = 5;
+		_step_block = 4;
 		lcd_selftest_screen_step(2, 8, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Y", _indicator);
 
-		_step_block = 6;
+		_step_block = 5;
 		lcd_selftest_screen_step(2, 14, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Z", _indicator);
 
-		_step_block = 7;
+		_step_block = 6;
 		lcd_selftest_screen_step(3, 0, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Bed", _indicator);
+
+        _step_block = 7;
+        lcd_selftest_screen_step(3, 9, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Hotend", _indicator);
 	}
 
 	if (_delay > 0) delay_keep_alive(_delay);
 	_progress++;
 
-	return (_progress > _progress_scale * 2) ? 0 : _progress;
+	return (_progress >= _progress_scale * 2) ? 0 : _progress;
 }
 
 static void lcd_selftest_screen_step(int _row, int _col, int _state, const char *_name, const char *_indicator)
@@ -7517,7 +7610,9 @@ void menu_lcd_lcdupdate_func(void)
 		if (lcd_oldcardstatus)
 		{
 			card.initsd();
-			LCD_MESSAGERPGM(_i("Card inserted"));////MSG_SD_INSERTED c=0 r=0
+               LCD_MESSAGERPGM(_T(WELCOME_MSG));
+               bMain=false;                       // flag (i.e. 'fake parameter') for 'lcd_sdcard_menu()' function
+               menu_submenu(lcd_sdcard_menu);
 			//get_description();
 		}
 		else

+ 11 - 2
Firmware/variants/1_75mm_MK2-RAMBo10a-E3Dv6full.h

@@ -1,6 +1,7 @@
 #ifndef CONFIGURATION_PRUSA_H
 #define CONFIGURATION_PRUSA_H
 
+#include <limits.h>
 /*------------------------------------
 GENERAL SETTINGS
 *------------------------------------*/
@@ -102,10 +103,18 @@ EXTRUDER SETTINGS
 *------------------------------------*/
 
 // Mintemps
-#define HEATER_0_MINTEMP 15
+#define HEATER_0_MINTEMP 30
 #define HEATER_1_MINTEMP 5
 #define HEATER_2_MINTEMP 5
-#define BED_MINTEMP 15
+#define HEATER_MINTEMP_DELAY 15000                // [ms] ! if changed, check maximal allowed value @ ShortTimer
+#if HEATER_MINTEMP_DELAY>USHRT_MAX
+#error "Check maximal allowed value @ ShortTimer (see HEATER_MINTEMP_DELAY definition)"
+#endif
+#define BED_MINTEMP 30
+#define BED_MINTEMP_DELAY 50000                   // [ms] ! if changed, check maximal allowed value @ ShortTimer
+#if BED_MINTEMP_DELAY>USHRT_MAX
+#error "Check maximal allowed value @ ShortTimer (see BED_MINTEMP_DELAY definition)"
+#endif
 
 // Maxtemps
 #if defined(E3D_PT100_EXTRUDER_WITH_AMP) || defined(E3D_PT100_EXTRUDER_NO_AMP)

+ 11 - 2
Firmware/variants/1_75mm_MK2-RAMBo13a-E3Dv6full.h

@@ -1,6 +1,7 @@
 #ifndef CONFIGURATION_PRUSA_H
 #define CONFIGURATION_PRUSA_H
 
+#include <limits.h>
 /*------------------------------------
 GENERAL SETTINGS
 *------------------------------------*/
@@ -102,10 +103,18 @@ EXTRUDER SETTINGS
 *------------------------------------*/
 
 // Mintemps
-#define HEATER_0_MINTEMP 15
+#define HEATER_0_MINTEMP 30
 #define HEATER_1_MINTEMP 5
 #define HEATER_2_MINTEMP 5
-#define BED_MINTEMP 15
+#define HEATER_MINTEMP_DELAY 15000                // [ms] ! if changed, check maximal allowed value @ ShortTimer
+#if HEATER_MINTEMP_DELAY>USHRT_MAX
+#error "Check maximal allowed value @ ShortTimer (see HEATER_MINTEMP_DELAY definition)"
+#endif
+#define BED_MINTEMP 30
+#define BED_MINTEMP_DELAY 50000                   // [ms] ! if changed, check maximal allowed value @ ShortTimer
+#if BED_MINTEMP_DELAY>USHRT_MAX
+#error "Check maximal allowed value @ ShortTimer (see BED_MINTEMP_DELAY definition)"
+#endif
 
 // Maxtemps
 #if defined(E3D_PT100_EXTRUDER_WITH_AMP) || defined(E3D_PT100_EXTRUDER_NO_AMP)

+ 11 - 2
Firmware/variants/1_75mm_MK25-RAMBo10a-E3Dv6full.h

@@ -1,6 +1,7 @@
 #ifndef CONFIGURATION_PRUSA_H
 #define CONFIGURATION_PRUSA_H
 
+#include <limits.h>
 /*------------------------------------
  GENERAL SETTINGS
  *------------------------------------*/
@@ -155,10 +156,18 @@
  *------------------------------------*/
 
 // Mintemps
-#define HEATER_0_MINTEMP 15
+#define HEATER_0_MINTEMP 30
 #define HEATER_1_MINTEMP 5
 #define HEATER_2_MINTEMP 5
-#define BED_MINTEMP 15
+#define HEATER_MINTEMP_DELAY 15000                // [ms] ! if changed, check maximal allowed value @ ShortTimer
+#if HEATER_MINTEMP_DELAY>USHRT_MAX
+#error "Check maximal allowed value @ ShortTimer (see HEATER_MINTEMP_DELAY definition)"
+#endif
+#define BED_MINTEMP 30
+#define BED_MINTEMP_DELAY 50000                   // [ms] ! if changed, check maximal allowed value @ ShortTimer
+#if BED_MINTEMP_DELAY>USHRT_MAX
+#error "Check maximal allowed value @ ShortTimer (see BED_MINTEMP_DELAY definition)"
+#endif
 
 // Maxtemps
 #if defined(E3D_PT100_EXTRUDER_WITH_AMP) || defined(E3D_PT100_EXTRUDER_NO_AMP)

+ 11 - 2
Firmware/variants/1_75mm_MK25-RAMBo13a-E3Dv6full.h

@@ -1,6 +1,7 @@
 #ifndef CONFIGURATION_PRUSA_H
 #define CONFIGURATION_PRUSA_H
 
+#include <limits.h>
 /*------------------------------------
  GENERAL SETTINGS
  *------------------------------------*/
@@ -156,10 +157,18 @@
  *------------------------------------*/
 
 // Mintemps
-#define HEATER_0_MINTEMP 15
+#define HEATER_0_MINTEMP 30
 #define HEATER_1_MINTEMP 5
 #define HEATER_2_MINTEMP 5
-#define BED_MINTEMP 15
+#define HEATER_MINTEMP_DELAY 15000                // [ms] ! if changed, check maximal allowed value @ ShortTimer
+#if HEATER_MINTEMP_DELAY>USHRT_MAX
+#error "Check maximal allowed value @ ShortTimer (see HEATER_MINTEMP_DELAY definition)"
+#endif
+#define BED_MINTEMP 30
+#define BED_MINTEMP_DELAY 50000                   // [ms] ! if changed, check maximal allowed value @ ShortTimer
+#if BED_MINTEMP_DELAY>USHRT_MAX
+#error "Check maximal allowed value @ ShortTimer (see BED_MINTEMP_DELAY definition)"
+#endif
 
 // Maxtemps
 #if defined(E3D_PT100_EXTRUDER_WITH_AMP) || defined(E3D_PT100_EXTRUDER_NO_AMP)

+ 9 - 0
Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h

@@ -1,6 +1,7 @@
 #ifndef CONFIGURATION_PRUSA_H
 #define CONFIGURATION_PRUSA_H
 
+#include <limits.h>
 /*------------------------------------
  GENERAL SETTINGS
  *------------------------------------*/
@@ -276,7 +277,15 @@
 #define HEATER_0_MINTEMP 15
 #define HEATER_1_MINTEMP 5
 #define HEATER_2_MINTEMP 5
+#define HEATER_MINTEMP_DELAY 15000                // [ms] ! if changed, check maximal allowed value @ ShortTimer
+#if HEATER_MINTEMP_DELAY>USHRT_MAX
+#error "Check maximal allowed value @ ShortTimer (see HEATER_MINTEMP_DELAY definition)"
+#endif
 #define BED_MINTEMP 15
+#define BED_MINTEMP_DELAY 50000                   // [ms] ! if changed, check maximal allowed value @ ShortTimer
+#if BED_MINTEMP_DELAY>USHRT_MAX
+#error "Check maximal allowed value @ ShortTimer (see BED_MINTEMP_DELAY definition)"
+#endif
 
 // Maxtemps
 #if defined(E3D_PT100_EXTRUDER_WITH_AMP) || defined(E3D_PT100_EXTRUDER_NO_AMP)

+ 1 - 1
README.md

@@ -20,7 +20,7 @@ The script downloads Arduino with our modifications and Rambo board support inst
 
    a. install `"Arduino Software IDE"` for your preferred operating system  
 `https://www.arduino.cc -> Software->Downloads`  
-it is recommended to use older version `"1.6.9"`, as it is used on out build server to produce official builds.  
+it is recommended to use version `"1.8.5"`, as it is used on out build server to produce official builds.  
 _note: in the case of persistent compilation problems, check the version of the currently used C/C++ compiler (GCC) - should be `4.8.1`; version can be verified by entering the command  
 `avr-gcc --version`  
 if you are not sure where the file is placed (depends on how `"Arduino Software IDE"` was installed), you can use the search feature within the file system_  

+ 146 - 0
Tests/AutoDeplete_test.cpp

@@ -0,0 +1,146 @@
+/**
+ * @file
+ * @author Marek Bel
+ */
+
+#include "catch.hpp"
+
+#include "../Firmware/AutoDeplete.h"
+
+TEST_CASE( "AutoDeplete test.", "[AutoDeplete]" )
+{
+    CHECK(ad_allDepleted() == false);
+
+    CHECK(ad_getAlternative(0) == 0);
+    CHECK(ad_getAlternative(1) == 1);
+    CHECK(ad_getAlternative(2) == 2);
+    CHECK(ad_getAlternative(3) == 3);
+    CHECK(ad_getAlternative(4) == 4);
+
+    ad_markDepleted(1);
+
+    CHECK(ad_getAlternative(0) == 0);
+    CHECK(ad_getAlternative(1) == 2);
+    CHECK(ad_getAlternative(2) == 2);
+    CHECK(ad_getAlternative(3) == 3);
+    CHECK(ad_getAlternative(4) == 4);
+    CHECK(ad_allDepleted() == false);
+
+    ad_markDepleted(3);
+
+    CHECK(ad_getAlternative(0) == 0);
+    CHECK(ad_getAlternative(1) == 2);
+    CHECK(ad_getAlternative(2) == 2);
+    CHECK(ad_getAlternative(3) == 4);
+    CHECK(ad_getAlternative(4) == 4);
+    CHECK(ad_allDepleted() == false);
+
+    ad_markDepleted(4);
+
+    CHECK(ad_getAlternative(0) == 0);
+    CHECK(ad_getAlternative(1) == 2);
+    CHECK(ad_getAlternative(2) == 2);
+    CHECK(ad_getAlternative(3) == 0);
+    CHECK(ad_getAlternative(4) == 0);
+    CHECK(ad_allDepleted() == false);
+
+    ad_markDepleted(4);
+
+    CHECK(ad_getAlternative(0) == 0);
+    CHECK(ad_getAlternative(1) == 2);
+    CHECK(ad_getAlternative(2) == 2);
+    CHECK(ad_getAlternative(3) == 0);
+    CHECK(ad_getAlternative(4) == 0);
+    CHECK(ad_allDepleted() == false);
+
+    ad_markDepleted(0);
+
+    CHECK(ad_getAlternative(0) == 2);
+    CHECK(ad_getAlternative(1) == 2);
+    CHECK(ad_getAlternative(2) == 2);
+    CHECK(ad_getAlternative(3) == 2);
+    CHECK(ad_getAlternative(4) == 2);
+    CHECK(ad_allDepleted() == false);
+
+    ad_markDepleted(2);
+
+    CHECK(ad_getAlternative(0) == 0);
+    CHECK(ad_getAlternative(1) == 1);
+    CHECK(ad_getAlternative(2) == 2);
+    CHECK(ad_getAlternative(3) == 3);
+    CHECK(ad_getAlternative(4) == 4);
+    CHECK(ad_allDepleted() == true);
+
+    ad_markDepleted(2);
+
+    CHECK(ad_getAlternative(0) == 0);
+    CHECK(ad_getAlternative(1) == 1);
+    CHECK(ad_getAlternative(2) == 2);
+    CHECK(ad_getAlternative(3) == 3);
+    CHECK(ad_getAlternative(4) == 4);
+    CHECK(ad_allDepleted() == true);
+
+    ad_markLoaded(4);
+
+    CHECK(ad_getAlternative(0) == 4);
+    CHECK(ad_getAlternative(1) == 4);
+    CHECK(ad_getAlternative(2) == 4);
+    CHECK(ad_getAlternative(3) == 4);
+    CHECK(ad_getAlternative(4) == 4);
+    CHECK(ad_allDepleted() == false);
+
+    ad_markLoaded(0);
+
+    CHECK(ad_getAlternative(0) == 0);
+    CHECK(ad_getAlternative(1) == 4);
+    CHECK(ad_getAlternative(2) == 4);
+    CHECK(ad_getAlternative(3) == 4);
+    CHECK(ad_getAlternative(4) == 4);
+    CHECK(ad_allDepleted() == false);
+
+    ad_markLoaded(3);
+
+    CHECK(ad_getAlternative(0) == 0);
+    CHECK(ad_getAlternative(1) == 3);
+    CHECK(ad_getAlternative(2) == 3);
+    CHECK(ad_getAlternative(3) == 3);
+    CHECK(ad_getAlternative(4) == 4);
+    CHECK(ad_allDepleted() == false);
+
+    ad_markLoaded(3);
+
+    CHECK(ad_getAlternative(0) == 0);
+    CHECK(ad_getAlternative(1) == 3);
+    CHECK(ad_getAlternative(2) == 3);
+    CHECK(ad_getAlternative(3) == 3);
+    CHECK(ad_getAlternative(4) == 4);
+    CHECK(ad_allDepleted() == false);
+
+    ad_markLoaded(2);
+
+    CHECK(ad_getAlternative(0) == 0);
+    CHECK(ad_getAlternative(1) == 2);
+    CHECK(ad_getAlternative(2) == 2);
+    CHECK(ad_getAlternative(3) == 3);
+    CHECK(ad_getAlternative(4) == 4);
+    CHECK(ad_allDepleted() == false);
+
+    ad_markLoaded(1);
+
+    CHECK(ad_getAlternative(0) == 0);
+    CHECK(ad_getAlternative(1) == 1);
+    CHECK(ad_getAlternative(2) == 2);
+    CHECK(ad_getAlternative(3) == 3);
+    CHECK(ad_getAlternative(4) == 4);
+    CHECK(ad_allDepleted() == false);
+
+    ad_markLoaded(1);
+
+    CHECK(ad_getAlternative(0) == 0);
+    CHECK(ad_getAlternative(1) == 1);
+    CHECK(ad_getAlternative(2) == 2);
+    CHECK(ad_getAlternative(3) == 3);
+    CHECK(ad_getAlternative(4) == 4);
+    CHECK(ad_allDepleted() == false);
+
+}

+ 1 - 1
build.sh

@@ -12,7 +12,7 @@ if [ ! -f "PF-build-env-Linux64-$BUILD_ENV.zip" ]; then
 fi
 
 if [ ! -d "../../PF-build-env-$BUILD_ENV" ]; then
-    unzip PF-build-env-Linux64-$BUILD_ENV.zip -d ../../PF-build-env-$BUILD_ENV || exit 4
+    unzip -q PF-build-env-Linux64-$BUILD_ENV.zip -d ../../PF-build-env-$BUILD_ENV || exit 4
 fi
 
 cd ../../PF-build-env-$BUILD_ENV || exit 5