diff --git a/Firmware/Configuration.h b/Firmware/Configuration.h index 33a72fc80..387b10e15 100644 --- a/Firmware/Configuration.h +++ b/Firmware/Configuration.h @@ -5,11 +5,10 @@ #include "Configuration_prusa.h" // Firmware version -#define FW_version "3.0.10-8" +#define FW_version "3.0.12-RC2" #define FW_PRUSA3D_MAGIC "PRUSA3DFW" #define FW_PRUSA3D_MAGIC_LEN 10 - // The total size of the EEPROM is // 4096 for the Atmega2560 #define EEPROM_TOP 4096 @@ -44,6 +43,10 @@ #define EEPROM_BED_CORRECTION_REAR (EEPROM_BED_CORRECTION_FRONT-1) #define EEPROM_TOSHIBA_FLASH_AIR_COMPATIBLITY (EEPROM_BED_CORRECTION_REAR-1) #define EEPROM_PRINT_FLAG (EEPROM_TOSHIBA_FLASH_AIR_COMPATIBLITY-1) +#define EEPROM_PROBE_TEMP_SHIFT (EEPROM_PRINT_FLAG - 2*5) //5 x int for storing pinda probe temp shift relative to 50 C; unit: motor steps +#define EEPROM_TEMP_CAL_ACTIVE (EEPROM_PROBE_TEMP_SHIFT - 1) +#define EEPROM_BOWDEN_LENGTH (EEPROM_TEMP_CAL_ACTIVE - 2*4) //4 x int for bowden lengths for multimaterial +#define EEPROM_CALIBRATION_STATUS_PINDA (EEPROM_BOWDEN_LENGTH - 1) //0 - not calibrated; 1 - calibrated // Currently running firmware, each digit stored as uint16_t. // The flavor differentiates a dev, alpha, beta, release candidate or a release version. @@ -246,7 +249,6 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of //#define DISABLE_MAX_ENDSTOPS //#define DISABLE_MIN_ENDSTOPS - // Disable max endstops for compatibility with endstop checking routine #if defined(COREXY) && !defined(DISABLE_MAX_ENDSTOPS) #define DISABLE_MAX_ENDSTOPS @@ -265,10 +267,10 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of #define DISABLE_E false // For all extruders #define DISABLE_INACTIVE_EXTRUDER true //disable only inactive extruders and keep active extruder enabled -#define INVERT_X_DIR true // for Mendel set to false, for Orca set to true +#define INVERT_X_DIR false // for Mendel set to false, for Orca set to true #define INVERT_Y_DIR false // for Mendel set to true, for Orca set to false -#define INVERT_Z_DIR true // for Mendel set to false, for Orca set to true -#define INVERT_E0_DIR false // for direct drive extruder v9 set to true, for geared extruder set to false +#define INVERT_Z_DIR false // for Mendel set to false, for Orca set to true +#define INVERT_E0_DIR true // for direct drive extruder v9 set to true, for geared extruder set to false #define INVERT_E1_DIR false // for direct drive extruder v9 set to true, for geared extruder set to false #define INVERT_E2_DIR false // for direct drive extruder v9 set to true, for geared extruder set to false @@ -422,8 +424,8 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of // #define EXTRUDER_OFFSET_Y {0.0, 5.00} // (in mm) for each extruder, offset of the hotend on the Y axis // The speed change that does not require acceleration (i.e. the software might assume it can be done instantaneously) -#define DEFAULT_XJERK 5.0 // (mm/sec) -#define DEFAULT_YJERK 5.0 // (mm/sec) +#define DEFAULT_XJERK 10.0 // (mm/sec) +#define DEFAULT_YJERK 10.0 // (mm/sec) #define DEFAULT_ZJERK 0.2 // (mm/sec) #define DEFAULT_EJERK 2.5 // (mm/sec) @@ -459,8 +461,8 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of #define SDSUPPORT // Enable SD Card Support in Hardware Console //#define SDSLOW // Use slower SD transfer mode (not normally needed - uncomment if you're getting volume init error) #define SD_CHECK_AND_RETRY // Use CRC checks and retries on the SD communication -#define ENCODER_PULSES_PER_STEP 2 // Increase if you have a high resolution encoder -#define ENCODER_STEPS_PER_MENU_ITEM 2 // Set according to ENCODER_PULSES_PER_STEP or your liking +#define ENCODER_PULSES_PER_STEP 4 // Increase if you have a high resolution encoder +#define ENCODER_STEPS_PER_MENU_ITEM 1 // Set according to ENCODER_PULSES_PER_STEP or your liking //#define ULTIMAKERCONTROLLER //as available from the Ultimaker online store. //#define ULTIPANEL //the UltiPanel as on Thingiverse //#define LCD_FEEDBACK_FREQUENCY_HZ 1000 // this is the tone frequency the buzzer plays when on UI feedback. ie Screen Click @@ -700,17 +702,17 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of // (unsigned char*)EEPROM_CALIBRATION_STATUS enum CalibrationStatus { - // Freshly assembled, needs to peform a self-test and the XYZ calibration. - CALIBRATION_STATUS_ASSEMBLED = 255, + // Freshly assembled, needs to peform a self-test and the XYZ calibration. + CALIBRATION_STATUS_ASSEMBLED = 255, - // For the wizard: self test has been performed, now the XYZ calibration is needed. - // CALIBRATION_STATUS_XYZ_CALIBRATION = 250, + // For the wizard: self test has been performed, now the XYZ calibration is needed. + // CALIBRATION_STATUS_XYZ_CALIBRATION = 250, - // For the wizard: factory assembled, needs to run Z calibration. - CALIBRATION_STATUS_Z_CALIBRATION = 240, + // For the wizard: factory assembled, needs to run Z calibration. + CALIBRATION_STATUS_Z_CALIBRATION = 240, - // The XYZ calibration has been performed, now it remains to run the V2Calibration.gcode. - CALIBRATION_STATUS_LIVE_ADJUST = 230, + // The XYZ calibration has been performed, now it remains to run the V2Calibration.gcode. + CALIBRATION_STATUS_LIVE_ADJUST = 230, // Calibrated, ready to print. CALIBRATION_STATUS_CALIBRATED = 1, diff --git a/Firmware/ConfigurationStore.h b/Firmware/ConfigurationStore.h index c73b29bcb..164aed681 100644 --- a/Firmware/ConfigurationStore.h +++ b/Firmware/ConfigurationStore.h @@ -22,5 +22,6 @@ FORCE_INLINE void Config_RetrieveSettings() { Config_ResetDefault(); Config_Prin inline uint8_t calibration_status() { return eeprom_read_byte((uint8_t*)EEPROM_CALIBRATION_STATUS); } inline uint8_t calibration_status_store(uint8_t status) { eeprom_update_byte((uint8_t*)EEPROM_CALIBRATION_STATUS, status); } +inline bool calibration_status_pinda() { return eeprom_read_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA); } #endif//CONFIG_STORE_H diff --git a/Firmware/Marlin.h b/Firmware/Marlin.h index bc8e21420..96f1607c4 100644 --- a/Firmware/Marlin.h +++ b/Firmware/Marlin.h @@ -1,334 +1,354 @@ -// Tonokip RepRap firmware rewrite based off of Hydra-mmm firmware. -// License: GPL - -#ifndef MARLIN_H -#define MARLIN_H - -#define FORCE_INLINE __attribute__((always_inline)) inline - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - - -#include "fastio.h" -#include "Configuration.h" -#include "pins.h" - -#ifndef AT90USB -#define HardwareSerial_h // trick to disable the standard HWserial -#endif - -#if (ARDUINO >= 100) -# include "Arduino.h" -#else -# include "WProgram.h" -#endif - -// Arduino < 1.0.0 does not define this, so we need to do it ourselves -#ifndef analogInputToDigitalPin -# define analogInputToDigitalPin(p) ((p) + A0) -#endif - -#ifdef AT90USB -#include "HardwareSerial.h" -#endif - -#include "MarlinSerial.h" - -#ifndef cbi -#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) -#endif -#ifndef sbi -#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) -#endif - -#include "WString.h" - -#ifdef AT90USB - #ifdef BTENABLED - #define MYSERIAL bt - #else - #define MYSERIAL Serial - #endif // BTENABLED -#else - #define MYSERIAL MSerial -#endif - -#define SERIAL_PROTOCOL(x) (MYSERIAL.print(x)) -#define SERIAL_PROTOCOL_F(x,y) (MYSERIAL.print(x,y)) -#define SERIAL_PROTOCOLPGM(x) (serialprintPGM(PSTR(x))) -#define SERIAL_PROTOCOLRPGM(x) (serialprintPGM((x))) -#define SERIAL_PROTOCOLLN(x) (MYSERIAL.print(x),MYSERIAL.write('\n')) -#define SERIAL_PROTOCOLLNPGM(x) (serialprintPGM(PSTR(x)),MYSERIAL.write('\n')) -#define SERIAL_PROTOCOLLNRPGM(x) (serialprintPGM((x)),MYSERIAL.write('\n')) - - -extern const char errormagic[] PROGMEM; -extern const char echomagic[] PROGMEM; - -#define SERIAL_ERROR_START (serialprintPGM(errormagic)) -#define SERIAL_ERROR(x) SERIAL_PROTOCOL(x) -#define SERIAL_ERRORPGM(x) SERIAL_PROTOCOLPGM(x) -#define SERIAL_ERRORRPGM(x) SERIAL_PROTOCOLRPGM(x) -#define SERIAL_ERRORLN(x) SERIAL_PROTOCOLLN(x) -#define SERIAL_ERRORLNPGM(x) SERIAL_PROTOCOLLNPGM(x) -#define SERIAL_ERRORLNRPGM(x) SERIAL_PROTOCOLLNRPGM(x) - -#define SERIAL_ECHO_START (serialprintPGM(echomagic)) -#define SERIAL_ECHO(x) SERIAL_PROTOCOL(x) -#define SERIAL_ECHOPGM(x) SERIAL_PROTOCOLPGM(x) -#define SERIAL_ECHORPGM(x) SERIAL_PROTOCOLRPGM(x) -#define SERIAL_ECHOLN(x) SERIAL_PROTOCOLLN(x) -#define SERIAL_ECHOLNPGM(x) SERIAL_PROTOCOLLNPGM(x) -#define SERIAL_ECHOLNRPGM(x) SERIAL_PROTOCOLLNRPGM(x) - -#define SERIAL_ECHOPAIR(name,value) (serial_echopair_P(PSTR(name),(value))) - -void serial_echopair_P(const char *s_P, float v); -void serial_echopair_P(const char *s_P, double v); -void serial_echopair_P(const char *s_P, unsigned long v); - - -//Things to write to serial from Program memory. Saves 400 to 2k of RAM. -FORCE_INLINE void serialprintPGM(const char *str) -{ - char ch=pgm_read_byte(str); - while(ch) - { - MYSERIAL.write(ch); - ch=pgm_read_byte(++str); - } -} - -bool is_buffer_empty(); -void get_command(); -void process_commands(); -void ramming(); - -void manage_inactivity(bool ignore_stepper_queue=false); - -#if defined(X_ENABLE_PIN) && X_ENABLE_PIN > -1 - #define enable_x() WRITE(X_ENABLE_PIN, X_ENABLE_ON) - #define disable_x() { WRITE(X_ENABLE_PIN,!X_ENABLE_ON); axis_known_position[X_AXIS] = false; } -#else - #define enable_x() ; - #define disable_x() ; -#endif - -#if defined(Y_ENABLE_PIN) && Y_ENABLE_PIN > -1 - #ifdef Y_DUAL_STEPPER_DRIVERS - #define enable_y() { WRITE(Y_ENABLE_PIN, Y_ENABLE_ON); WRITE(Y2_ENABLE_PIN, Y_ENABLE_ON); } - #define disable_y() { WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON); WRITE(Y2_ENABLE_PIN, !Y_ENABLE_ON); axis_known_position[Y_AXIS] = false; } - #else - #define enable_y() WRITE(Y_ENABLE_PIN, Y_ENABLE_ON) - #define disable_y() { WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON); axis_known_position[Y_AXIS] = false; } - #endif -#else - #define enable_y() ; - #define disable_y() ; -#endif - -#if defined(Z_ENABLE_PIN) && Z_ENABLE_PIN > -1 - #if defined(Z_AXIS_ALWAYS_ON) - #ifdef Z_DUAL_STEPPER_DRIVERS - #define enable_z() { WRITE(Z_ENABLE_PIN, Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN, Z_ENABLE_ON); } - #define disable_z() { WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN,!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; } - #else - #define enable_z() WRITE(Z_ENABLE_PIN, Z_ENABLE_ON) - #define disable_z() ; - #endif - #else - #ifdef Z_DUAL_STEPPER_DRIVERS - #define enable_z() { WRITE(Z_ENABLE_PIN, Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN, Z_ENABLE_ON); } - #define disable_z() { WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN,!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; } - #else - #define enable_z() WRITE(Z_ENABLE_PIN, Z_ENABLE_ON) - #define disable_z() { WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; } - #endif - #endif -#else - #define enable_z() ; - #define disable_z() ; -#endif - - - - -//#if defined(Z_ENABLE_PIN) && Z_ENABLE_PIN > -1 -//#ifdef Z_DUAL_STEPPER_DRIVERS -//#define enable_z() { WRITE(Z_ENABLE_PIN, Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN, Z_ENABLE_ON); } -//#define disable_z() { WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN,!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; } -//#else -//#define enable_z() WRITE(Z_ENABLE_PIN, Z_ENABLE_ON) -//#define disable_z() { WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; } -//#endif -//#else -//#define enable_z() ; -//#define disable_z() ; -//#endif - - -#if defined(E0_ENABLE_PIN) && (E0_ENABLE_PIN > -1) - #define enable_e0() WRITE(E0_ENABLE_PIN, E_ENABLE_ON) - #define disable_e0() WRITE(E0_ENABLE_PIN,!E_ENABLE_ON) -#else - #define enable_e0() /* nothing */ - #define disable_e0() /* nothing */ -#endif - -#if (EXTRUDERS > 1) && defined(E1_ENABLE_PIN) && (E1_ENABLE_PIN > -1) - #define enable_e1() WRITE(E1_ENABLE_PIN, E_ENABLE_ON) - #define disable_e1() WRITE(E1_ENABLE_PIN,!E_ENABLE_ON) -#else - #define enable_e1() /* nothing */ - #define disable_e1() /* nothing */ -#endif - -#if (EXTRUDERS > 2) && defined(E2_ENABLE_PIN) && (E2_ENABLE_PIN > -1) - #define enable_e2() WRITE(E2_ENABLE_PIN, E_ENABLE_ON) - #define disable_e2() WRITE(E2_ENABLE_PIN,!E_ENABLE_ON) -#else - #define enable_e2() /* nothing */ - #define disable_e2() /* nothing */ -#endif - - -enum AxisEnum {X_AXIS=0, Y_AXIS=1, Z_AXIS=2, E_AXIS=3, X_HEAD=4, Y_HEAD=5}; - - -void FlushSerialRequestResend(); -void ClearToSend(); - -void get_coordinates(); -void prepare_move(); -void kill(const char *full_screen_message = NULL); -void Stop(); - -bool IsStopped(); - -//put an ASCII command at the end of the current buffer. -void enquecommand(const char *cmd, bool from_progmem = false); -//put an ASCII command at the end of the current buffer, read from flash -#define enquecommand_P(cmd) enquecommand(cmd, true) -void enquecommand_front(const char *cmd, bool from_progmem = false); -//put an ASCII command at the end of the current buffer, read from flash -#define enquecommand_P(cmd) enquecommand(cmd, true) -#define enquecommand_front_P(cmd) enquecommand_front(cmd, true) -void repeatcommand_front(); -// Remove all lines from the command queue. -void cmdqueue_reset(); - -void prepare_arc_move(char isclockwise); -void clamp_to_software_endstops(float target[3]); - -void refresh_cmd_timeout(void); - -#ifdef FAST_PWM_FAN -void setPwmFrequency(uint8_t pin, int val); -#endif - -#ifndef CRITICAL_SECTION_START - #define CRITICAL_SECTION_START unsigned char _sreg = SREG; cli(); - #define CRITICAL_SECTION_END SREG = _sreg; -#endif //CRITICAL_SECTION_START - -extern float homing_feedrate[]; -extern bool axis_relative_modes[]; -extern int feedmultiply; -extern int extrudemultiply; // Sets extrude multiply factor (in percent) for all extruders -extern bool volumetric_enabled; -extern int extruder_multiply[EXTRUDERS]; // sets extrude multiply factor (in percent) for each extruder individually -extern float filament_size[EXTRUDERS]; // cross-sectional area of filament (in millimeters), typically around 1.75 or 2.85, 0 disables the volumetric calculations for the extruder. -extern float volumetric_multiplier[EXTRUDERS]; // reciprocal of cross-sectional area of filament (in square millimeters), stored this way to reduce computational burden in planner -extern float current_position[NUM_AXIS] ; -extern float destination[NUM_AXIS] ; -extern float add_homing[3]; -extern float min_pos[3]; -extern float max_pos[3]; -extern bool axis_known_position[3]; -extern float zprobe_zoffset; -extern int fanSpeed; -extern void homeaxis(int axis); - - -#ifdef FAN_SOFT_PWM -extern unsigned char fanSpeedSoftPwm; -#endif - -#ifdef FILAMENT_SENSOR - extern float filament_width_nominal; //holds the theoretical filament diameter ie., 3.00 or 1.75 - extern bool filament_sensor; //indicates that filament sensor readings should control extrusion - extern float filament_width_meas; //holds the filament diameter as accurately measured - extern signed char measurement_delay[]; //ring buffer to delay measurement - extern int delay_index1, delay_index2; //index into ring buffer - extern float delay_dist; //delay distance counter - extern int meas_delay_cm; //delay distance -#endif - -#ifdef FWRETRACT -extern bool autoretract_enabled; -extern bool retracted[EXTRUDERS]; -extern float retract_length, retract_length_swap, retract_feedrate, retract_zlift; -extern float retract_recover_length, retract_recover_length_swap, retract_recover_feedrate; -#endif - -extern unsigned long starttime; -extern unsigned long stoptime; -extern bool is_usb_printing; -extern bool homing_flag; -extern bool loading_flag; -extern unsigned int usb_printing_counter; - -extern unsigned long kicktime; - -extern unsigned long total_filament_used; -void save_statistics(unsigned long _total_filament_used, unsigned long _total_print_time); -extern unsigned int heating_status; -extern unsigned int status_number; -extern unsigned int heating_status_counter; -extern bool custom_message; -extern unsigned int custom_message_type; -extern unsigned int custom_message_state; -extern unsigned long PingTime; +// Tonokip RepRap firmware rewrite based off of Hydra-mmm firmware. +// License: GPL + +#ifndef MARLIN_H +#define MARLIN_H + +#define FORCE_INLINE __attribute__((always_inline)) inline + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +#include "fastio.h" +#include "Configuration.h" +#include "pins.h" + +#ifndef AT90USB +#define HardwareSerial_h // trick to disable the standard HWserial +#endif + +#if (ARDUINO >= 100) +# include "Arduino.h" +#else +# include "WProgram.h" +#endif + +// Arduino < 1.0.0 does not define this, so we need to do it ourselves +#ifndef analogInputToDigitalPin +# define analogInputToDigitalPin(p) ((p) + A0) +#endif + +#ifdef AT90USB +#include "HardwareSerial.h" +#endif + +#include "MarlinSerial.h" + +#ifndef cbi +#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) +#endif +#ifndef sbi +#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) +#endif + +#include "WString.h" + +#ifdef AT90USB + #ifdef BTENABLED + #define MYSERIAL bt + #else + #define MYSERIAL Serial + #endif // BTENABLED +#else + #define MYSERIAL MSerial +#endif + +#define SERIAL_PROTOCOL(x) (MYSERIAL.print(x)) +#define SERIAL_PROTOCOL_F(x,y) (MYSERIAL.print(x,y)) +#define SERIAL_PROTOCOLPGM(x) (serialprintPGM(PSTR(x))) +#define SERIAL_PROTOCOLRPGM(x) (serialprintPGM((x))) +#define SERIAL_PROTOCOLLN(x) (MYSERIAL.print(x),MYSERIAL.write('\n')) +#define SERIAL_PROTOCOLLNPGM(x) (serialprintPGM(PSTR(x)),MYSERIAL.write('\n')) +#define SERIAL_PROTOCOLLNRPGM(x) (serialprintPGM((x)),MYSERIAL.write('\n')) + + +extern const char errormagic[] PROGMEM; +extern const char echomagic[] PROGMEM; + +#define SERIAL_ERROR_START (serialprintPGM(errormagic)) +#define SERIAL_ERROR(x) SERIAL_PROTOCOL(x) +#define SERIAL_ERRORPGM(x) SERIAL_PROTOCOLPGM(x) +#define SERIAL_ERRORRPGM(x) SERIAL_PROTOCOLRPGM(x) +#define SERIAL_ERRORLN(x) SERIAL_PROTOCOLLN(x) +#define SERIAL_ERRORLNPGM(x) SERIAL_PROTOCOLLNPGM(x) +#define SERIAL_ERRORLNRPGM(x) SERIAL_PROTOCOLLNRPGM(x) + +#define SERIAL_ECHO_START (serialprintPGM(echomagic)) +#define SERIAL_ECHO(x) SERIAL_PROTOCOL(x) +#define SERIAL_ECHOPGM(x) SERIAL_PROTOCOLPGM(x) +#define SERIAL_ECHORPGM(x) SERIAL_PROTOCOLRPGM(x) +#define SERIAL_ECHOLN(x) SERIAL_PROTOCOLLN(x) +#define SERIAL_ECHOLNPGM(x) SERIAL_PROTOCOLLNPGM(x) +#define SERIAL_ECHOLNRPGM(x) SERIAL_PROTOCOLLNRPGM(x) + +#define SERIAL_ECHOPAIR(name,value) (serial_echopair_P(PSTR(name),(value))) + +void serial_echopair_P(const char *s_P, float v); +void serial_echopair_P(const char *s_P, double v); +void serial_echopair_P(const char *s_P, unsigned long v); + + +//Things to write to serial from Program memory. Saves 400 to 2k of RAM. +FORCE_INLINE void serialprintPGM(const char *str) +{ + char ch=pgm_read_byte(str); + while(ch) + { + MYSERIAL.write(ch); + ch=pgm_read_byte(++str); + } +} + +bool is_buffer_empty(); +void get_command(); +void process_commands(); +void ramming(); + +void manage_inactivity(bool ignore_stepper_queue=false); + +#if defined(X_ENABLE_PIN) && X_ENABLE_PIN > -1 + #define enable_x() WRITE(X_ENABLE_PIN, X_ENABLE_ON) + #define disable_x() { WRITE(X_ENABLE_PIN,!X_ENABLE_ON); axis_known_position[X_AXIS] = false; } +#else + #define enable_x() ; + #define disable_x() ; +#endif + +#if defined(Y_ENABLE_PIN) && Y_ENABLE_PIN > -1 + #ifdef Y_DUAL_STEPPER_DRIVERS + #define enable_y() { WRITE(Y_ENABLE_PIN, Y_ENABLE_ON); WRITE(Y2_ENABLE_PIN, Y_ENABLE_ON); } + #define disable_y() { WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON); WRITE(Y2_ENABLE_PIN, !Y_ENABLE_ON); axis_known_position[Y_AXIS] = false; } + #else + #define enable_y() WRITE(Y_ENABLE_PIN, Y_ENABLE_ON) + #define disable_y() { WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON); axis_known_position[Y_AXIS] = false; } + #endif +#else + #define enable_y() ; + #define disable_y() ; +#endif + +#if defined(Z_ENABLE_PIN) && Z_ENABLE_PIN > -1 + #if defined(Z_AXIS_ALWAYS_ON) + #ifdef Z_DUAL_STEPPER_DRIVERS + #define enable_z() { WRITE(Z_ENABLE_PIN, Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN, Z_ENABLE_ON); } + #define disable_z() { WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN,!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; } + #else + #define enable_z() WRITE(Z_ENABLE_PIN, Z_ENABLE_ON) + #define disable_z() ; + #endif + #else + #ifdef Z_DUAL_STEPPER_DRIVERS + #define enable_z() { WRITE(Z_ENABLE_PIN, Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN, Z_ENABLE_ON); } + #define disable_z() { WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN,!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; } + #else + #define enable_z() WRITE(Z_ENABLE_PIN, Z_ENABLE_ON) + #define disable_z() { WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; } + #endif + #endif +#else + #define enable_z() ; + #define disable_z() ; +#endif + + + + +//#if defined(Z_ENABLE_PIN) && Z_ENABLE_PIN > -1 +//#ifdef Z_DUAL_STEPPER_DRIVERS +//#define enable_z() { WRITE(Z_ENABLE_PIN, Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN, Z_ENABLE_ON); } +//#define disable_z() { WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN,!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; } +//#else +//#define enable_z() WRITE(Z_ENABLE_PIN, Z_ENABLE_ON) +//#define disable_z() { WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; } +//#endif +//#else +//#define enable_z() ; +//#define disable_z() ; +//#endif + + +#if defined(E0_ENABLE_PIN) && (E0_ENABLE_PIN > -1) + #define enable_e0() WRITE(E0_ENABLE_PIN, E_ENABLE_ON) + #define disable_e0() WRITE(E0_ENABLE_PIN,!E_ENABLE_ON) +#else + #define enable_e0() /* nothing */ + #define disable_e0() /* nothing */ +#endif + +#if (EXTRUDERS > 1) && defined(E1_ENABLE_PIN) && (E1_ENABLE_PIN > -1) + #define enable_e1() WRITE(E1_ENABLE_PIN, E_ENABLE_ON) + #define disable_e1() WRITE(E1_ENABLE_PIN,!E_ENABLE_ON) +#else + #define enable_e1() /* nothing */ + #define disable_e1() /* nothing */ +#endif + +#if (EXTRUDERS > 2) && defined(E2_ENABLE_PIN) && (E2_ENABLE_PIN > -1) + #define enable_e2() WRITE(E2_ENABLE_PIN, E_ENABLE_ON) + #define disable_e2() WRITE(E2_ENABLE_PIN,!E_ENABLE_ON) +#else + #define enable_e2() /* nothing */ + #define disable_e2() /* nothing */ +#endif + + +enum AxisEnum {X_AXIS=0, Y_AXIS=1, Z_AXIS=2, E_AXIS=3, X_HEAD=4, Y_HEAD=5}; + + +void FlushSerialRequestResend(); +void ClearToSend(); + +void get_coordinates(); +void prepare_move(); +void kill(const char *full_screen_message = NULL); +void Stop(); + +bool IsStopped(); + +//put an ASCII command at the end of the current buffer. +void enquecommand(const char *cmd, bool from_progmem = false); +//put an ASCII command at the end of the current buffer, read from flash +#define enquecommand_P(cmd) enquecommand(cmd, true) +void enquecommand_front(const char *cmd, bool from_progmem = false); +//put an ASCII command at the end of the current buffer, read from flash +#define enquecommand_P(cmd) enquecommand(cmd, true) +#define enquecommand_front_P(cmd) enquecommand_front(cmd, true) +void repeatcommand_front(); +// Remove all lines from the command queue. +void cmdqueue_reset(); + +void prepare_arc_move(char isclockwise); +void clamp_to_software_endstops(float target[3]); + +void refresh_cmd_timeout(void); + +#ifdef FAST_PWM_FAN +void setPwmFrequency(uint8_t pin, int val); +#endif + +#ifndef CRITICAL_SECTION_START + #define CRITICAL_SECTION_START unsigned char _sreg = SREG; cli(); + #define CRITICAL_SECTION_END SREG = _sreg; +#endif //CRITICAL_SECTION_START + +extern float homing_feedrate[]; +extern bool axis_relative_modes[]; +extern int feedmultiply; +extern int extrudemultiply; // Sets extrude multiply factor (in percent) for all extruders +extern bool volumetric_enabled; +extern int extruder_multiply[EXTRUDERS]; // sets extrude multiply factor (in percent) for each extruder individually +extern float filament_size[EXTRUDERS]; // cross-sectional area of filament (in millimeters), typically around 1.75 or 2.85, 0 disables the volumetric calculations for the extruder. +extern float volumetric_multiplier[EXTRUDERS]; // reciprocal of cross-sectional area of filament (in square millimeters), stored this way to reduce computational burden in planner +extern float current_position[NUM_AXIS] ; +extern float destination[NUM_AXIS] ; +extern float add_homing[3]; +extern float min_pos[3]; +extern float max_pos[3]; +extern bool axis_known_position[3]; +extern float zprobe_zoffset; +extern int fanSpeed; +extern void homeaxis(int axis); + + +#ifdef FAN_SOFT_PWM +extern unsigned char fanSpeedSoftPwm; +#endif + +#ifdef FILAMENT_SENSOR + extern float filament_width_nominal; //holds the theoretical filament diameter ie., 3.00 or 1.75 + extern bool filament_sensor; //indicates that filament sensor readings should control extrusion + extern float filament_width_meas; //holds the filament diameter as accurately measured + extern signed char measurement_delay[]; //ring buffer to delay measurement + extern int delay_index1, delay_index2; //index into ring buffer + extern float delay_dist; //delay distance counter + extern int meas_delay_cm; //delay distance +#endif + +#ifdef FWRETRACT +extern bool autoretract_enabled; +extern bool retracted[EXTRUDERS]; +extern float retract_length, retract_length_swap, retract_feedrate, retract_zlift; +extern float retract_recover_length, retract_recover_length_swap, retract_recover_feedrate; +#endif + +extern unsigned long starttime; +extern unsigned long stoptime; +extern int bowden_length[4]; +extern bool is_usb_printing; +extern bool homing_flag; +extern bool temp_cal_active; +extern bool loading_flag; +extern unsigned int usb_printing_counter; + +extern unsigned long kicktime; + +extern unsigned long total_filament_used; +void save_statistics(unsigned long _total_filament_used, unsigned long _total_print_time); +extern unsigned int heating_status; +extern unsigned int status_number; +extern unsigned int heating_status_counter; +extern bool custom_message; +extern unsigned int custom_message_type; +extern unsigned int custom_message_state; +extern char snmm_filaments_used; +extern unsigned long PingTime; + extern bool fan_state[2]; extern int fan_edge_counter[2]; extern int fan_speed[2]; - - -// Handling multiple extruders pins -extern uint8_t active_extruder; - -#ifdef DIGIPOT_I2C -extern void digipot_i2c_set_current( int channel, float current ); -extern void digipot_i2c_init(); -#endif - -#endif - - - - - -extern void calculate_volumetric_multipliers(); - -// Similar to the default Arduino delay function, -// but it keeps the background tasks running. -extern void delay_keep_alive(int ms); - -extern void check_babystep(); - -#ifdef DIS - -void d_setup(); -float d_ReadData(); -void bed_analysis(float x_dimension, float y_dimension, int x_points_num, int y_points_num, float shift_x, float shift_y); - -#endif \ No newline at end of file + +// Handling multiple extruders pins +extern uint8_t active_extruder; + +#ifdef DIGIPOT_I2C +extern void digipot_i2c_set_current( int channel, float current ); +extern void digipot_i2c_init(); +#endif + +#endif + +//Long pause +extern int saved_feedmultiply; +extern float HotendTempBckp; +extern int fanSpeedBckp; +extern float pause_lastpos[4]; +extern unsigned long pause_time; +extern unsigned long start_pause_print; + +extern bool mesh_bed_leveling_flag; +extern bool mesh_bed_run_from_menu; + +extern float distance_from_min[3]; +extern float angleDiff; + +extern void calculate_volumetric_multipliers(); + +// Similar to the default Arduino delay function, +// but it keeps the background tasks running. +extern void delay_keep_alive(unsigned int ms); + +extern void check_babystep(); + +extern void long_pause(); + +#ifdef DIS + +void d_setup(); +float d_ReadData(); +void bed_analysis(float x_dimension, float y_dimension, int x_points_num, int y_points_num, float shift_x, float shift_y); + +#endif +float temp_comp_interpolation(float temperature); +void temp_compensation_apply(); +void temp_compensation_start(); +void wait_for_heater(long codenum); +void serialecho_temperatures(); \ No newline at end of file diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index d738c769d..eabf8a0c4 100644 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -27,14 +27,6 @@ http://reprap.org/pipermail/reprap-dev/2011-May/003323.html */ - - - - - - - - #include "Marlin.h" #ifdef ENABLE_AUTO_BED_LEVELING @@ -50,7 +42,6 @@ #endif #include "ultralcd.h" -#include "pat9125.h" #include "Configuration_prusa.h" #include "planner.h" #include "stepper.h" @@ -64,6 +55,11 @@ #include "math.h" #include "util.h" +#ifdef HAVE_TMC2130_DRIVERS +#include "tmc2130.h" +#endif //HAVE_TMC2130_DRIVERS + + #ifdef BLINKM #include "BlinkM.h" #include "Wire.h" @@ -101,7 +97,6 @@ // PRUSA CODES // P F - Returns FW versions // P R - Returns revision of printer -// P Y - Starts filament allignment process for multicolor // G0 -> G1 // G1 - Coordinated Movement X Y Z E @@ -255,15 +250,31 @@ int extruder_multiply[EXTRUDERS] = {100 #endif }; +int bowden_length[4]; + bool is_usb_printing = false; bool homing_flag = false; +bool temp_cal_active = false; + unsigned long kicktime = millis()+100000; unsigned int usb_printing_counter; int lcd_change_fil_state = 0; + int feedmultiplyBckp = 100; +float HotendTempBckp = 0; +int fanSpeedBckp = 0; +float pause_lastpos[4]; +unsigned long pause_time = 0; +unsigned long start_pause_print = millis(); + +unsigned long load_filament_time; + +bool mesh_bed_leveling_flag = false; +bool mesh_bed_run_from_menu = false; + unsigned char lang_selected = 0; int8_t FarmMode = 0; @@ -278,11 +289,16 @@ bool custom_message; bool loading_flag = false; unsigned int custom_message_type; unsigned int custom_message_state; +char snmm_filaments_used = 0; + +float distance_from_min[3]; +float angleDiff; bool fan_state[2]; int fan_edge_counter[2]; int fan_speed[2]; + bool volumetric_enabled = false; float filament_size[EXTRUDERS] = { DEFAULT_NOMINAL_FILAMENT_DIA #if EXTRUDERS > 1 @@ -898,7 +914,7 @@ int er_progress = 0; void factory_reset(char level, bool quiet) { lcd_implementation_clear(); - + int cursor_pos = 0; switch (level) { // Level 0: Language reset @@ -969,6 +985,9 @@ void factory_reset(char level, bool quiet) } + break; + case 4: + bowden_menu(); break; default: @@ -984,179 +1003,183 @@ void factory_reset(char level, bool quiet) // are initialized by the main() routine provided by the Arduino framework. void setup() { - setup_killpin(); - setup_powerhold(); - MYSERIAL.begin(BAUDRATE); - SERIAL_PROTOCOLLNPGM("start"); - SERIAL_ECHO_START; + setup_killpin(); + setup_powerhold(); + MYSERIAL.begin(BAUDRATE); + SERIAL_PROTOCOLLNPGM("start"); + SERIAL_ECHO_START; #if 0 - SERIAL_ECHOLN("Reading eeprom from 0 to 100: start"); - for (int i = 0; i < 4096; ++ i) { - int b = eeprom_read_byte((unsigned char*)i); - if (b != 255) { - SERIAL_ECHO(i); - SERIAL_ECHO(":"); - SERIAL_ECHO(b); - SERIAL_ECHOLN(""); - } - } - SERIAL_ECHOLN("Reading eeprom from 0 to 100: done"); - #endif + SERIAL_ECHOLN("Reading eeprom from 0 to 100: start"); + for (int i = 0; i < 4096; ++i) { + int b = eeprom_read_byte((unsigned char*)i); + if (b != 255) { + SERIAL_ECHO(i); + SERIAL_ECHO(":"); + SERIAL_ECHO(b); + SERIAL_ECHOLN(""); + } + } + SERIAL_ECHOLN("Reading eeprom from 0 to 100: done"); +#endif - // Check startup - does nothing if bootloader sets MCUSR to 0 - byte mcu = MCUSR; - if(mcu & 1) SERIAL_ECHOLNRPGM(MSG_POWERUP); - if(mcu & 2) SERIAL_ECHOLNRPGM(MSG_EXTERNAL_RESET); - if(mcu & 4) SERIAL_ECHOLNRPGM(MSG_BROWNOUT_RESET); - if(mcu & 8) SERIAL_ECHOLNRPGM(MSG_WATCHDOG_RESET); - if(mcu & 32) SERIAL_ECHOLNRPGM(MSG_SOFTWARE_RESET); - MCUSR=0; + // Check startup - does nothing if bootloader sets MCUSR to 0 + byte mcu = MCUSR; + if (mcu & 1) SERIAL_ECHOLNRPGM(MSG_POWERUP); + if (mcu & 2) SERIAL_ECHOLNRPGM(MSG_EXTERNAL_RESET); + if (mcu & 4) SERIAL_ECHOLNRPGM(MSG_BROWNOUT_RESET); + if (mcu & 8) SERIAL_ECHOLNRPGM(MSG_WATCHDOG_RESET); + if (mcu & 32) SERIAL_ECHOLNRPGM(MSG_SOFTWARE_RESET); + MCUSR = 0; - //SERIAL_ECHORPGM(MSG_MARLIN); - //SERIAL_ECHOLNRPGM(VERSION_STRING); - - #ifdef STRING_VERSION_CONFIG_H - #ifdef STRING_CONFIG_H_AUTHOR - SERIAL_ECHO_START; - SERIAL_ECHORPGM(MSG_CONFIGURATION_VER); - SERIAL_ECHOPGM(STRING_VERSION_CONFIG_H); - SERIAL_ECHORPGM(MSG_AUTHOR); - SERIAL_ECHOLNPGM(STRING_CONFIG_H_AUTHOR); - SERIAL_ECHOPGM("Compiled: "); - SERIAL_ECHOLNPGM(__DATE__); - #endif - #endif - - SERIAL_ECHO_START; - SERIAL_ECHORPGM(MSG_FREE_MEMORY); - SERIAL_ECHO(freeMemory()); - SERIAL_ECHORPGM(MSG_PLANNER_BUFFER_BYTES); - SERIAL_ECHOLN((int)sizeof(block_t)*BLOCK_BUFFER_SIZE); - lcd_update_enable(false); - // loads data from EEPROM if available else uses defaults (and resets step acceleration rate) - Config_RetrieveSettings(); - SdFatUtil::set_stack_guard(); //writes magic number at the end of static variables to protect against overwriting static memory by stack - tp_init(); // Initialize temperature loop - plan_init(); // Initialize planner; - watchdog_init(); - st_init(); // Initialize stepper, this enables interrupts! - setup_photpin(); - servo_init(); - // Reset the machine correction matrix. - // It does not make sense to load the correction matrix until the machine is homed. - world2machine_reset(); - - lcd_init(); - - pat9125_init(200, 200); - - if (!READ(BTN_ENC)) - { - _delay_ms(1000); - if (!READ(BTN_ENC)) - { - lcd_implementation_clear(); - - - lcd_printPGM(PSTR("Factory RESET")); - - - SET_OUTPUT(BEEPER); - WRITE(BEEPER, HIGH); - - while (!READ(BTN_ENC)); - - WRITE(BEEPER, LOW); - - + //SERIAL_ECHORPGM(MSG_MARLIN); + //SERIAL_ECHOLNRPGM(VERSION_STRING); - _delay_ms(2000); - - char level = reset_menu(); - factory_reset(level, false); - - switch (level) { - case 0: _delay_ms(0); break; - case 1: _delay_ms(0); break; - case 2: _delay_ms(0); break; - case 3: _delay_ms(0); break; - } - // _delay_ms(100); -/* -#ifdef MESH_BED_LEVELING - _delay_ms(2000); +#ifdef STRING_VERSION_CONFIG_H +#ifdef STRING_CONFIG_H_AUTHOR + SERIAL_ECHO_START; + SERIAL_ECHORPGM(MSG_CONFIGURATION_VER); + SERIAL_ECHOPGM(STRING_VERSION_CONFIG_H); + SERIAL_ECHORPGM(MSG_AUTHOR); + SERIAL_ECHOLNPGM(STRING_CONFIG_H_AUTHOR); + SERIAL_ECHOPGM("Compiled: "); + SERIAL_ECHOLNPGM(__DATE__); +#endif +#endif - if (!READ(BTN_ENC)) - { - WRITE(BEEPER, HIGH); - _delay_ms(100); - WRITE(BEEPER, LOW); - _delay_ms(200); - WRITE(BEEPER, HIGH); - _delay_ms(100); - WRITE(BEEPER, LOW); + SERIAL_ECHO_START; + SERIAL_ECHORPGM(MSG_FREE_MEMORY); + SERIAL_ECHO(freeMemory()); + SERIAL_ECHORPGM(MSG_PLANNER_BUFFER_BYTES); + SERIAL_ECHOLN((int)sizeof(block_t)*BLOCK_BUFFER_SIZE); + lcd_update_enable(false); + // loads data from EEPROM if available else uses defaults (and resets step acceleration rate) + Config_RetrieveSettings(); + SdFatUtil::set_stack_guard(); //writes magic number at the end of static variables to protect against overwriting static memory by stack + tp_init(); // Initialize temperature loop + plan_init(); // Initialize planner; + watchdog_init(); + st_init(); // Initialize stepper, this enables interrupts! + setup_photpin(); + servo_init(); + // Reset the machine correction matrix. + // It does not make sense to load the correction matrix until the machine is homed. + world2machine_reset(); - int _z = 0; - calibration_status_store(CALIBRATION_STATUS_CALIBRATED); - EEPROM_save_B(EEPROM_BABYSTEP_X, &_z); - EEPROM_save_B(EEPROM_BABYSTEP_Y, &_z); - EEPROM_save_B(EEPROM_BABYSTEP_Z, &_z); - } - else - { + lcd_init(); + if (!READ(BTN_ENC)) + { + _delay_ms(1000); + if (!READ(BTN_ENC)) + { + lcd_implementation_clear(); - WRITE(BEEPER, HIGH); - _delay_ms(100); - WRITE(BEEPER, LOW); - } -#endif // mesh */ - - } - } - else - { - _delay_ms(1000); // wait 1sec to display the splash screen - } - + lcd_printPGM(PSTR("Factory RESET")); - #if defined(CONTROLLERFAN_PIN) && CONTROLLERFAN_PIN > -1 - SET_OUTPUT(CONTROLLERFAN_PIN); //Set pin used for driver cooling fan - #endif - #ifdef DIGIPOT_I2C - digipot_i2c_init(); - #endif - setup_homepin(); + SET_OUTPUT(BEEPER); + WRITE(BEEPER, HIGH); + + while (!READ(BTN_ENC)); + + WRITE(BEEPER, LOW); + + + + _delay_ms(2000); + + char level = reset_menu(); + factory_reset(level, false); + + switch (level) { + case 0: _delay_ms(0); break; + case 1: _delay_ms(0); break; + case 2: _delay_ms(0); break; + case 3: _delay_ms(0); break; + } + // _delay_ms(100); + /* + #ifdef MESH_BED_LEVELING + _delay_ms(2000); + + if (!READ(BTN_ENC)) + { + WRITE(BEEPER, HIGH); + _delay_ms(100); + WRITE(BEEPER, LOW); + _delay_ms(200); + WRITE(BEEPER, HIGH); + _delay_ms(100); + WRITE(BEEPER, LOW); + + int _z = 0; + calibration_status_store(CALIBRATION_STATUS_CALIBRATED); + EEPROM_save_B(EEPROM_BABYSTEP_X, &_z); + EEPROM_save_B(EEPROM_BABYSTEP_Y, &_z); + EEPROM_save_B(EEPROM_BABYSTEP_Z, &_z); + } + else + { + + WRITE(BEEPER, HIGH); + _delay_ms(100); + WRITE(BEEPER, LOW); + } + #endif // mesh */ + + } + } + else + { + _delay_ms(1000); // wait 1sec to display the splash screen + } + + + +#if defined(CONTROLLERFAN_PIN) && CONTROLLERFAN_PIN > -1 + SET_OUTPUT(CONTROLLERFAN_PIN); //Set pin used for driver cooling fan +#endif + +#ifdef DIGIPOT_I2C + digipot_i2c_init(); +#endif + setup_homepin(); #if defined(Z_AXIS_ALWAYS_ON) - enable_z(); + enable_z(); #endif - farm_mode = eeprom_read_byte((uint8_t*)EEPROM_FARM_MODE); - EEPROM_read_B(EEPROM_FARM_NUMBER, &farm_no); - if (farm_mode == 0xFF && farm_no == 0) farm_mode = false; //if farm_mode has not been stored to eeprom yet and farm number is set to zero, deactivate farm mode - if (farm_mode) - { - prusa_statistics(8); - } + farm_mode = eeprom_read_byte((uint8_t*)EEPROM_FARM_MODE); + EEPROM_read_B(EEPROM_FARM_NUMBER, &farm_no); + if ((farm_mode == 0xFF && farm_no == 0) || (farm_no == 0xFFFF)) farm_mode = false; //if farm_mode has not been stored to eeprom yet and farm number is set to zero or EEPROM is fresh, deactivate farm mode + if (farm_no == 0xFFFF) farm_no = 0; + if (farm_mode) + { + prusa_statistics(8); + } - // Enable Toshiba FlashAir SD card / WiFi enahanced card. - card.ToshibaFlashAir_enable(eeprom_read_byte((unsigned char*)EEPROM_TOSHIBA_FLASH_AIR_COMPATIBLITY) == 1); - // Force SD card update. Otherwise the SD card update is done from loop() on card.checkautostart(false), - // but this times out if a blocking dialog is shown in setup(). - card.initsd(); + // Enable Toshiba FlashAir SD card / WiFi enahanced card. + card.ToshibaFlashAir_enable(eeprom_read_byte((unsigned char*)EEPROM_TOSHIBA_FLASH_AIR_COMPATIBLITY) == 1); + // Force SD card update. Otherwise the SD card update is done from loop() on card.checkautostart(false), + // but this times out if a blocking dialog is shown in setup(). + card.initsd(); - if (eeprom_read_dword((uint32_t*)(EEPROM_TOP-4)) == 0x0ffffffff && - eeprom_read_dword((uint32_t*)(EEPROM_TOP-8)) == 0x0ffffffff && - eeprom_read_dword((uint32_t*)(EEPROM_TOP-12)) == 0x0ffffffff) { - // Maiden startup. The firmware has been loaded and first started on a virgin RAMBo board, - // where all the EEPROM entries are set to 0x0ff. - // Once a firmware boots up, it forces at least a language selection, which changes - // EEPROM_LANG to number lower than 0x0ff. - // 1) Set a high power mode. - eeprom_write_byte((uint8_t*)EEPROM_SILENT, 0); - } + if (eeprom_read_dword((uint32_t*)(EEPROM_TOP - 4)) == 0x0ffffffff && + eeprom_read_dword((uint32_t*)(EEPROM_TOP - 8)) == 0x0ffffffff && + eeprom_read_dword((uint32_t*)(EEPROM_TOP - 12)) == 0x0ffffffff) { + // Maiden startup. The firmware has been loaded and first started on a virgin RAMBo board, + // where all the EEPROM entries are set to 0x0ff. + // Once a firmware boots up, it forces at least a language selection, which changes + // EEPROM_LANG to number lower than 0x0ff. + // 1) Set a high power mode. + eeprom_write_byte((uint8_t*)EEPROM_SILENT, 0); + } +#ifdef SNMM + if (eeprom_read_dword((uint32_t*)EEPROM_BOWDEN_LENGTH) == 0x0ffffffff) { //bowden length used for SNMM + int _z = BOWDEN_LENGTH; + for(int i = 0; i<4; i++) EEPROM_save_B(EEPROM_BOWDEN_LENGTH + i * 2, &_z); + } +#endif // In the future, somewhere here would one compare the current firmware version against the firmware version stored in the EEPROM. // If they differ, an update procedure may need to be performed. At the end of this block, the current firmware version @@ -1165,6 +1188,15 @@ void setup() if (lang_selected >= LANG_NUM){ lcd_mylang(); } + + if (eeprom_read_byte((uint8_t*)EEPROM_TEMP_CAL_ACTIVE) == 255) { + eeprom_write_byte((uint8_t*)EEPROM_TEMP_CAL_ACTIVE, 0); + temp_cal_active = false; + } else temp_cal_active = eeprom_read_byte((uint8_t*)EEPROM_TEMP_CAL_ACTIVE); + + if (eeprom_read_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA) == 255) { + eeprom_write_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, 0); + } check_babystep(); //checking if Z babystep is in allowed range @@ -1177,10 +1209,15 @@ void setup() } else if (calibration_status() == CALIBRATION_STATUS_LIVE_ADJUST) { // Show the message. lcd_show_fullscreen_message_and_wait_P(MSG_BABYSTEP_Z_NOT_SET); + lcd_update_enable(true); + } else if (calibration_status() == CALIBRATION_STATUS_CALIBRATED && temp_cal_active == true && calibration_status_pinda() == false) { + lcd_show_fullscreen_message_and_wait_P(MSG_PINDA_NOT_CALIBRATED); + lcd_update_enable(true); } else if (calibration_status() == CALIBRATION_STATUS_Z_CALIBRATION) { // Show the message. lcd_show_fullscreen_message_and_wait_P(MSG_FOLLOW_CALIBRATION_FLOW); } + for (int i = 0; i<4; i++) EEPROM_read_B(EEPROM_BOWDEN_LENGTH + i * 2, &bowden_length[i]); lcd_update_enable(true); // Store the currently running firmware into an eeprom, @@ -1321,13 +1358,9 @@ void loop() } //check heater every n milliseconds manage_heater(); - manage_inactivity(); + isPrintPaused ? manage_inactivity(true) : manage_inactivity(false); checkHitEndstops(); lcd_update(); - - pat9125_update(); - - tmc2130_check_overtemp(); } void get_command() @@ -1527,7 +1560,8 @@ void get_command() SERIAL_PROTOCOLLNRPGM(MSG_FILE_PRINTED); stoptime=millis(); char time[30]; - unsigned long t=(stoptime-starttime)/1000; + unsigned long t=(stoptime-starttime-pause_time)/1000; + pause_time = 0; int hours, minutes; minutes=(t/60)%60; hours=t/60/60; @@ -1772,89 +1806,46 @@ static float probe_pt(float x, float y, float z_before) { void homeaxis(int axis) { #define HOMEAXIS_DO(LETTER) \ -((LETTER##_MIN_PIN > -1 && LETTER##_HOME_DIR==-1) || (LETTER##_MAX_PIN > -1 && LETTER##_HOME_DIR==1)) - - if (axis==X_AXIS ? HOMEAXIS_DO(X) : - axis==Y_AXIS ? HOMEAXIS_DO(Y) : - 0) { - int axis_home_dir = home_dir(axis); - - #ifdef HAVE_TMC2130_DRIVERS - st_setSGHoming(axis); - - // Configuration to spreadCycle - tmc2130_write((axis == X_AXIS)? X_TMC2130_CS : Y_TMC2130_CS,0x0,0,0,0,0x01); - - tmc2130_write((axis == X_AXIS)? X_TMC2130_CS : Y_TMC2130_CS,0x6D,0,SG_THRESHOLD,0,0); - - tmc2130_write((axis == X_AXIS)? X_TMC2130_CS : Y_TMC2130_CS,0x14,0,0,0,TCOOLTHRS); - #endif - - current_position[axis] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - - destination[axis] = 1.5 * max_length(axis) * axis_home_dir; - feedrate = homing_feedrate[axis]; - plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); - st_synchronize(); - - current_position[axis] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[axis] = -home_retract_mm(axis) * axis_home_dir; - plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); - st_synchronize(); - - destination[axis] = 2*home_retract_mm(axis) * axis_home_dir; - if(st_didLastHomingStall()) - feedrate = homing_feedrate[axis]; - else - feedrate = homing_feedrate[axis]/2 ; - plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); - st_synchronize(); - axis_is_at_home(axis); - destination[axis] = current_position[axis]; - feedrate = 0.0; - endstops_hit_on_purpose(); - axis_known_position[axis] = true; - - #ifdef HAVE_TMC2130_DRIVERS - // Configuration back to stealthChop - tmc2130_write((axis == X_AXIS)? X_TMC2130_CS : Y_TMC2130_CS,0x0,0,0,0,0x05); - - st_setSGHoming(0xFF); - st_resetSGflags(); - #endif - } - else if (axis==Z_AXIS ? HOMEAXIS_DO(Z) : - 0) { - int axis_home_dir = home_dir(axis); - - current_position[axis] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - - destination[axis] = 1.5 * max_length(axis) * axis_home_dir; - feedrate = homing_feedrate[axis]; - plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); - st_synchronize(); - - current_position[axis] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - destination[axis] = -home_retract_mm(axis) * axis_home_dir; - plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); - st_synchronize(); - - destination[axis] = 2*home_retract_mm(axis) * axis_home_dir; - feedrate = homing_feedrate[axis]/2 ; - plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); - st_synchronize(); - axis_is_at_home(axis); - destination[axis] = current_position[axis]; - feedrate = 0.0; - endstops_hit_on_purpose(); - axis_known_position[axis] = true; - } -} + ((LETTER##_MIN_PIN > -1 && LETTER##_HOME_DIR==-1) || (LETTER##_MAX_PIN > -1 && LETTER##_HOME_DIR==1)) + if (axis==X_AXIS ? HOMEAXIS_DO(X) : + axis==Y_AXIS ? HOMEAXIS_DO(Y) : + axis==Z_AXIS ? HOMEAXIS_DO(Z) : + 0) { + int axis_home_dir = home_dir(axis); +#ifdef HAVE_TMC2130_DRIVERS + tmc2130_st_home_enter(axis); +#endif //HAVE_TMC2130_DRIVERS + + current_position[axis] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + + destination[axis] = 1.5 * max_length(axis) * axis_home_dir; + feedrate = homing_feedrate[axis]; + plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); + st_synchronize(); + + current_position[axis] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[axis] = -home_retract_mm(axis) * axis_home_dir; + plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); + st_synchronize(); + + destination[axis] = 2*home_retract_mm(axis) * axis_home_dir; + feedrate = homing_feedrate[axis]/2 ; + plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); + st_synchronize(); + axis_is_at_home(axis); + destination[axis] = current_position[axis]; + feedrate = 0.0; + endstops_hit_on_purpose(); + axis_known_position[axis] = true; + +#ifdef HAVE_TMC2130_DRIVERS + tmc2130_st_home_enter(axis); +#endif //HAVE_TMC2130_DRIVERS + } +} void home_xy() { @@ -1920,7 +1911,7 @@ void trace() { noTone(BEEPER); delay(20); } - +/* void ramming() { // float tmp[4] = DEFAULT_MAX_FEEDRATE; if (current_temperature[0] < 230) { @@ -1975,10 +1966,10 @@ void ramming() { current_position[E_AXIS] += 4; plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); st_synchronize(); - /*current_position[X_AXIS] += 23; //delay - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600/60, active_extruder); //delay - current_position[X_AXIS] -= 23; //delay - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600/60, active_extruder); //delay*/ + //current_position[X_AXIS] += 23; //delay + //plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600/60, active_extruder); //delay + //current_position[X_AXIS] -= 23; //delay + //plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600/60, active_extruder); //delay delay(4700); max_feedrate[E_AXIS] = 80; current_position[E_AXIS] -= 92; @@ -2003,7 +1994,7 @@ void ramming() { } } - +*/ void process_commands() { #ifdef FILAMENT_RUNOUT_SUPPORT @@ -2032,7 +2023,13 @@ void process_commands() float tmp_motor_loud[3] = DEFAULT_PWM_MOTOR_CURRENT_LOUD; int8_t SilentMode; #endif - if(code_seen("PRUSA")){ + if (code_seen("M117")) { //moved to highest priority place to be able to to print strings which includes "G", "PRUSA" and "^" + starpos = (strchr(strchr_pointer + 5, '*')); + if (starpos != NULL) + *(starpos) = '\0'; + lcd_setstatus(strchr_pointer + 5); + } + else if(code_seen("PRUSA")){ if (code_seen("Ping")) { //PRUSA Ping if (farm_mode) { PingTime = millis(); @@ -2096,68 +2093,8 @@ void process_commands() } else if(code_seen("FR")) { // Factory full reset - factory_reset(0,true); - - }else if(code_seen("Y")) { //filaments adjustment at the beginning of print (for SNMM) - #ifdef SNMM - int extr; - SilentMode = eeprom_read_byte((uint8_t*)EEPROM_SILENT); //is silent mode or loud mode set - lcd_implementation_clear(); - lcd_display_message_fullscreen_P(MSG_FIL_ADJUSTING); - current_position[Z_AXIS] = 100; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 500, active_extruder); - digipot_current(2, E_MOTOR_HIGH_CURRENT); - for (extr = 1; extr < 4; extr++) { //we dont know which filament is in nozzle, but we want to load filament0, so all other filaments must unloaded - change_extr(extr); - ramming(); - } - change_extr(0); - current_position[E_AXIS] += FIL_LOAD_LENGTH; //loading filament0 into the nozzle - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 500, active_extruder); - st_synchronize(); - - for (extr = 1; extr < 4; extr++) { - digipot_current(2, E_MOTOR_LOW_CURRENT); //set lower current for extruder motors - change_extr(extr); - current_position[E_AXIS] += (FIL_LOAD_LENGTH + 3 * FIL_RETURN_LENGTH); //adjusting filaments - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 5000, active_extruder); - st_synchronize(); - digipot_current(2, tmp_motor_loud[2]); //set back to normal operation currents - current_position[E_AXIS] -= FIL_RETURN_LENGTH; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 500, active_extruder); - st_synchronize(); - } - - change_extr(0); - current_position[E_AXIS] += 25; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 10, active_extruder); - digipot_current(2, E_MOTOR_HIGH_CURRENT); - ramming(); - if (SilentMode == 1) digipot_current(2, tmp_motor[2]); //set back to normal operation currents - else digipot_current(2, tmp_motor_loud[2]); - st_synchronize(); - lcd_show_fullscreen_message_and_wait_P(MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ); - lcd_implementation_clear(); - lcd_printPGM(MSG_PLEASE_WAIT); - current_position[Z_AXIS] = 0; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 500, active_extruder); - st_synchronize(); - lcd_update_enable(true); - - #endif - } - else if (code_seen("SetF")) { -#ifdef SNMM - bool not_finished = (eeprom_read_byte((unsigned char*)EEPROM_PRINT_FLAG) != PRINT_FINISHED); - eeprom_update_byte((unsigned char*)EEPROM_PRINT_FLAG, PRINT_STARTED); - if (not_finished) enquecommand_front_P(PSTR("PRUSA Y")); -#endif - } - else if (code_seen("ResF")) { -#ifdef SNMM - eeprom_update_byte((unsigned char*)EEPROM_PRINT_FLAG, PRINT_FINISHED); -#endif - } + factory_reset(0,true); + } //else if (code_seen('Cal')) { // lcd_calibration(); // } @@ -2382,12 +2319,11 @@ void process_commands() prepare_arc_move(false); } break; - case 4: // G4 dwell - LCD_MESSAGERPGM(MSG_DWELL); + case 4: // G4 dwell codenum = 0; if(code_seen('P')) codenum = code_value(); // milliseconds to wait if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait - + if(codenum != 0) LCD_MESSAGERPGM(MSG_DWELL); st_synchronize(); codenum += millis(); // keep track of when we started waiting previous_millis_cmd = millis(); @@ -2514,7 +2450,7 @@ void process_commands() plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate, active_extruder); st_synchronize(); #endif // defined (Z_RAISE_BEFORE_HOMING) && (Z_RAISE_BEFORE_HOMING > 0) - #ifdef MESH_BED_LEVELING // If Mesh bed leveling, moxve X&Y to safe position for home + #if (defined(MESH_BED_LEVELING) && !defined(MK1BP)) // If Mesh bed leveling, moxve X&Y to safe position for home if (!(axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] )) { homeaxis(X_AXIS); @@ -2620,7 +2556,7 @@ void process_commands() // and correct the current_position to match the transformed coordinate system. world2machine_update_current(); -#ifdef MESH_BED_LEVELING +#if (defined(MESH_BED_LEVELING) && !defined(MK1BP)) if (code_seen(axis_codes[X_AXIS]) || code_seen(axis_codes[Y_AXIS]) || code_seen('W') || code_seen(axis_codes[Z_AXIS])) { } @@ -2837,6 +2773,134 @@ void process_commands() clean_up_after_endstop_move(); } break; + + + case 75: + { + for (int i = 40; i <= 110; i++) { + MYSERIAL.print(i); + MYSERIAL.print(" "); + MYSERIAL.println(temp_comp_interpolation(i));// / axis_steps_per_unit[Z_AXIS]); + } + } + break; + + case 76: //PINDA probe temperature calibration + { + setTargetBed(PINDA_MIN_T); + float zero_z; + int z_shift = 0; //unit: steps + int t_c; // temperature + + if (!(axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] && axis_known_position[Z_AXIS])) { + // We don't know where we are! HOME! + // Push the commands to the front of the message queue in the reverse order! + // There shall be always enough space reserved for these commands. + repeatcommand_front(); // repeat G76 with all its parameters + enquecommand_front_P((PSTR("G28 W0"))); + break; + } + SERIAL_ECHOLNPGM("PINDA probe calibration start"); + custom_message = true; + custom_message_type = 4; + custom_message_state = 1; + custom_message = MSG_TEMP_CALIBRATION; + current_position[X_AXIS] = PINDA_PREHEAT_X; + current_position[Y_AXIS] = PINDA_PREHEAT_Y; + current_position[Z_AXIS] = PINDA_PREHEAT_Z; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); + st_synchronize(); + + while (abs(degBed() - PINDA_MIN_T) > 1) { + delay_keep_alive(1000); + serialecho_temperatures(); + } + + //enquecommand_P(PSTR("M190 S50")); + for (int i = 0; i < PINDA_HEAT_T; i++) { + delay_keep_alive(1000); + serialecho_temperatures(); + } + eeprom_update_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, 0); //invalidate temp. calibration in case that in will be aborted during the calibration process + + current_position[Z_AXIS] = 5; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); + + current_position[X_AXIS] = pgm_read_float(bed_ref_points); + current_position[Y_AXIS] = pgm_read_float(bed_ref_points + 1); + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); + st_synchronize(); + + find_bed_induction_sensor_point_z(-1.f); + zero_z = current_position[Z_AXIS]; + + //current_position[Z_AXIS] + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("ZERO: "); + MYSERIAL.print(current_position[Z_AXIS]); + SERIAL_ECHOLNPGM(""); + + for (int i = 0; i<5; i++) { + SERIAL_ECHOPGM("Step: "); + MYSERIAL.print(i+2); + SERIAL_ECHOLNPGM("/6"); + custom_message_state = i + 2; + t_c = 60 + i * 10; + + setTargetBed(t_c); + current_position[X_AXIS] = PINDA_PREHEAT_X; + current_position[Y_AXIS] = PINDA_PREHEAT_Y; + current_position[Z_AXIS] = PINDA_PREHEAT_Z; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); + st_synchronize(); + while (degBed() < t_c) { + delay_keep_alive(1000); + serialecho_temperatures(); + } + for (int i = 0; i < PINDA_HEAT_T; i++) { + delay_keep_alive(1000); + serialecho_temperatures(); + } + current_position[Z_AXIS] = 5; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); + current_position[X_AXIS] = pgm_read_float(bed_ref_points); + current_position[Y_AXIS] = pgm_read_float(bed_ref_points + 1); + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); + st_synchronize(); + find_bed_induction_sensor_point_z(-1.f); + z_shift = (int)((current_position[Z_AXIS] - zero_z)*axis_steps_per_unit[Z_AXIS]); + + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("Temperature: "); + MYSERIAL.print(t_c); + SERIAL_ECHOPGM(" Z shift (mm):"); + MYSERIAL.print(current_position[Z_AXIS] - zero_z); + SERIAL_ECHOLNPGM(""); + + EEPROM_save_B(EEPROM_PROBE_TEMP_SHIFT + i*2, &z_shift); + + + } + custom_message_type = 0; + custom_message = false; + + eeprom_update_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, 1); + SERIAL_ECHOLNPGM("Temperature calibration done. Continue with pressing the knob."); + disable_x(); + disable_y(); + disable_z(); + disable_e0(); + disable_e1(); + disable_e2(); + setTargetBed(0); //set bed target temperature back to 0 + lcd_show_fullscreen_message_and_wait_P(MSG_TEMP_CALIBRATION_DONE); + lcd_update_enable(true); + lcd_update(2); + + + + } + break; #ifdef DIS case 77: @@ -2880,181 +2944,272 @@ void process_commands() * v Y-axis * */ - case 80: - case_G80: - { - // Firstly check if we know where we are - if ( !( axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] && axis_known_position[Z_AXIS] ) ){ - // We don't know where we are! HOME! - // Push the commands to the front of the message queue in the reverse order! - // There shall be always enough space reserved for these commands. - repeatcommand_front(); // repeat G80 with all its parameters - enquecommand_front_P((PSTR("G28 W0"))); - break; - } - // Save custom message state, set a new custom message state to display: Calibrating point 9. - bool custom_message_old = custom_message; - unsigned int custom_message_type_old = custom_message_type; - unsigned int custom_message_state_old = custom_message_state; - custom_message = true; - custom_message_type = 1; - custom_message_state = (MESH_MEAS_NUM_X_POINTS * MESH_MEAS_NUM_Y_POINTS) + 10; - lcd_update(1); - - mbl.reset(); + case 80: +#ifdef MK1BP + break; +#endif //MK1BP + case_G80: + { + mesh_bed_leveling_flag = true; + int8_t verbosity_level = 0; + static bool run = false; - // Reset baby stepping to zero, if the babystepping has already been loaded before. The babystepsTodo value will be - // consumed during the first movements following this statement. - babystep_undo(); + if (code_seen('V')) { + // Just 'V' without a number counts as V1. + char c = strchr_pointer[1]; + verbosity_level = (c == ' ' || c == '\t' || c == 0) ? 1 : code_value_short(); + } + // Firstly check if we know where we are + if (!(axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] && axis_known_position[Z_AXIS])) { + // We don't know where we are! HOME! + // Push the commands to the front of the message queue in the reverse order! + // There shall be always enough space reserved for these commands. + if (lcd_commands_type != LCD_COMMAND_STOP_PRINT) { + repeatcommand_front(); // repeat G80 with all its parameters + enquecommand_front_P((PSTR("G28 W0"))); + } + else { + mesh_bed_leveling_flag = false; + } + break; + } + + if (run == false && temp_cal_active == true && calibration_status_pinda() == true && target_temperature_bed >= 50) { + if (lcd_commands_type != LCD_COMMAND_STOP_PRINT) { + temp_compensation_start(); + run = true; + repeatcommand_front(); // repeat G80 with all its parameters + enquecommand_front_P((PSTR("G28 W0"))); + } + else { + mesh_bed_leveling_flag = false; + } + break; + } + run = false; + if (lcd_commands_type == LCD_COMMAND_STOP_PRINT) { + mesh_bed_leveling_flag = false; + break; + } + // Save custom message state, set a new custom message state to display: Calibrating point 9. + bool custom_message_old = custom_message; + unsigned int custom_message_type_old = custom_message_type; + unsigned int custom_message_state_old = custom_message_state; + custom_message = true; + custom_message_type = 1; + custom_message_state = (MESH_MEAS_NUM_X_POINTS * MESH_MEAS_NUM_Y_POINTS) + 10; + lcd_update(1); - // Cycle through all points and probe them - // First move up. During this first movement, the babystepping will be reverted. - current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], homing_feedrate[Z_AXIS]/60, active_extruder); - // The move to the first calibration point. - current_position[X_AXIS] = pgm_read_float(bed_ref_points); - current_position[Y_AXIS] = pgm_read_float(bed_ref_points+1); - world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]); -// mbl.get_meas_xy(0, 0, current_position[X_AXIS], current_position[Y_AXIS], false); - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], homing_feedrate[X_AXIS]/30, active_extruder); - // Wait until the move is finished. - st_synchronize(); - - int mesh_point = 0; - - int ix = 0; - int iy = 0; - - int XY_AXIS_FEEDRATE = homing_feedrate[X_AXIS]/20; - int Z_PROBE_FEEDRATE = homing_feedrate[Z_AXIS]/60; - int Z_LIFT_FEEDRATE = homing_feedrate[Z_AXIS]/40; - bool has_z = is_bed_z_jitter_data_valid(); - setup_for_endstop_move(false); - const char *kill_message = NULL; - while (mesh_point != MESH_MEAS_NUM_X_POINTS * MESH_MEAS_NUM_Y_POINTS) { - // Get coords of a measuring point. - ix = mesh_point % MESH_MEAS_NUM_X_POINTS; - iy = mesh_point / MESH_MEAS_NUM_X_POINTS; - if (iy & 1) ix = (MESH_MEAS_NUM_X_POINTS - 1) - ix; // Zig zag - float z0 = 0.f; - if (has_z && mesh_point > 0) { - uint16_t z_offset_u = eeprom_read_word((uint16_t*)(EEPROM_BED_CALIBRATION_Z_JITTER + 2 * (ix + iy * 3 - 1))); - z0 = mbl.z_values[0][0] + *reinterpret_cast(&z_offset_u) * 0.01; - #if 0 - SERIAL_ECHOPGM("Bed leveling, point: "); - MYSERIAL.print(mesh_point); - SERIAL_ECHOPGM(", calibration z: "); - MYSERIAL.print(z0, 5); - SERIAL_ECHOLNPGM(""); - #endif - } - - // Move Z up to MESH_HOME_Z_SEARCH. - current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], Z_LIFT_FEEDRATE, active_extruder); - st_synchronize(); + mbl.reset(); //reset mesh bed leveling - // Move to XY position of the sensor point. - current_position[X_AXIS] = pgm_read_float(bed_ref_points+2*mesh_point); - current_position[Y_AXIS] = pgm_read_float(bed_ref_points+2*mesh_point+1); - world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]); - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], XY_AXIS_FEEDRATE, active_extruder); - st_synchronize(); - - // Go down until endstop is hit - const float Z_CALIBRATION_THRESHOLD = 1.f; - if (! find_bed_induction_sensor_point_z((has_z && mesh_point > 0) ? z0 - Z_CALIBRATION_THRESHOLD : -10.f)) { - kill_message = MSG_BED_LEVELING_FAILED_POINT_LOW; - break; - } - if (MESH_HOME_Z_SEARCH - current_position[Z_AXIS] < 0.1f) { - kill_message = MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED; - break; - } - if (has_z && fabs(z0 - current_position[Z_AXIS]) > Z_CALIBRATION_THRESHOLD) { - kill_message = MSG_BED_LEVELING_FAILED_POINT_HIGH; - break; - } + // Reset baby stepping to zero, if the babystepping has already been loaded before. The babystepsTodo value will be + // consumed during the first movements following this statement. + babystep_undo(); - mbl.set_z(ix, iy, current_position[Z_AXIS]); + // Cycle through all points and probe them + // First move up. During this first movement, the babystepping will be reverted. + current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], homing_feedrate[Z_AXIS] / 60, active_extruder); + // The move to the first calibration point. + current_position[X_AXIS] = pgm_read_float(bed_ref_points); + current_position[Y_AXIS] = pgm_read_float(bed_ref_points + 1); + bool clamped = world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]); - custom_message_state--; - mesh_point++; - lcd_update(1); - } - current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS],current_position[Z_AXIS] , current_position[E_AXIS], Z_LIFT_FEEDRATE, active_extruder); - st_synchronize(); - if (mesh_point != MESH_MEAS_NUM_X_POINTS * MESH_MEAS_NUM_Y_POINTS) { - kill(kill_message); - } - clean_up_after_endstop_move(); + if (verbosity_level >= 1) { + clamped ? SERIAL_PROTOCOLPGM("First calibration point clamped.\n") : SERIAL_PROTOCOLPGM("No clamping for first calibration point.\n"); + } + // mbl.get_meas_xy(0, 0, current_position[X_AXIS], current_position[Y_AXIS], false); + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], homing_feedrate[X_AXIS] / 30, active_extruder); + // Wait until the move is finished. + st_synchronize(); - // Apply Z height correction aka baby stepping before mesh bed leveing gets activated. - babystep_apply(); + int mesh_point = 0; //index number of calibration point - bool eeprom_bed_correction_valid = eeprom_read_byte((unsigned char*)EEPROM_BED_CORRECTION_VALID) == 1; - for (uint8_t i = 0; i < 4; ++ i) { - unsigned char codes[4] = { 'L', 'R', 'F', 'B' }; - long correction = 0; - if (code_seen(codes[i])) - correction = code_value_long(); - else if (eeprom_bed_correction_valid) { - unsigned char *addr = (i < 2) ? - ((i == 0) ? (unsigned char*)EEPROM_BED_CORRECTION_LEFT : (unsigned char*)EEPROM_BED_CORRECTION_RIGHT) : - ((i == 2) ? (unsigned char*)EEPROM_BED_CORRECTION_FRONT : (unsigned char*)EEPROM_BED_CORRECTION_REAR); - correction = eeprom_read_int8(addr); - } - if (correction == 0) - continue; - float offset = float(correction) * 0.001f; - if (fabs(offset) > 0.101f) { - SERIAL_ERROR_START; - SERIAL_ECHOPGM("Excessive bed leveling correction: "); - SERIAL_ECHO(offset); - SERIAL_ECHOLNPGM(" microns"); - } else { - switch (i) { - case 0: - for (uint8_t row = 0; row < 3; ++ row) { - mbl.z_values[row][1] += 0.5f * offset; - mbl.z_values[row][0] += offset; - } - break; - case 1: - for (uint8_t row = 0; row < 3; ++ row) { - mbl.z_values[row][1] += 0.5f * offset; - mbl.z_values[row][2] += offset; - } - break; - case 2: - for (uint8_t col = 0; col < 3; ++ col) { - mbl.z_values[1][col] += 0.5f * offset; - mbl.z_values[0][col] += offset; - } - break; - case 3: - for (uint8_t col = 0; col < 3; ++ col) { - mbl.z_values[1][col] += 0.5f * offset; - mbl.z_values[2][col] += offset; - } - break; - } - } - } + int ix = 0; + int iy = 0; - mbl.upsample_3x3(); - mbl.active = 1; - go_home_with_z_lift(); + int XY_AXIS_FEEDRATE = homing_feedrate[X_AXIS] / 20; + int Z_PROBE_FEEDRATE = homing_feedrate[Z_AXIS] / 60; + int Z_LIFT_FEEDRATE = homing_feedrate[Z_AXIS] / 40; + bool has_z = is_bed_z_jitter_data_valid(); //checks if we have data from Z calibration (offsets of the Z heiths of the 8 calibration points from the first point) + if (verbosity_level >= 1) { + has_z ? SERIAL_PROTOCOLPGM("Z jitter data from Z cal. valid.\n") : SERIAL_PROTOCOLPGM("Z jitter data from Z cal. not valid.\n"); + } + setup_for_endstop_move(false); //save feedrate and feedmultiply, sets feedmultiply to 100 + const char *kill_message = NULL; + while (mesh_point != MESH_MEAS_NUM_X_POINTS * MESH_MEAS_NUM_Y_POINTS) { + if (verbosity_level >= 1) SERIAL_ECHOLNPGM(""); + // Get coords of a measuring point. + ix = mesh_point % MESH_MEAS_NUM_X_POINTS; // from 0 to MESH_NUM_X_POINTS - 1 + iy = mesh_point / MESH_MEAS_NUM_X_POINTS; + if (iy & 1) ix = (MESH_MEAS_NUM_X_POINTS - 1) - ix; // Zig zag + float z0 = 0.f; + if (has_z && mesh_point > 0) { + uint16_t z_offset_u = eeprom_read_word((uint16_t*)(EEPROM_BED_CALIBRATION_Z_JITTER + 2 * (ix + iy * 3 - 1))); + z0 = mbl.z_values[0][0] + *reinterpret_cast(&z_offset_u) * 0.01; + //#if 0 + if (verbosity_level >= 1) { + SERIAL_ECHOPGM("Bed leveling, point: "); + MYSERIAL.print(mesh_point); + SERIAL_ECHOPGM(", calibration z: "); + MYSERIAL.print(z0, 5); + SERIAL_ECHOLNPGM(""); + } + //#endif + } - // Restore custom message state - custom_message = custom_message_old; - custom_message_type = custom_message_type_old; - custom_message_state = custom_message_state_old; - lcd_update(1); - } - break; + // Move Z up to MESH_HOME_Z_SEARCH. + current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], Z_LIFT_FEEDRATE, active_extruder); + st_synchronize(); + + // Move to XY position of the sensor point. + current_position[X_AXIS] = pgm_read_float(bed_ref_points + 2 * mesh_point); + current_position[Y_AXIS] = pgm_read_float(bed_ref_points + 2 * mesh_point + 1); + + + + world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]); + if (verbosity_level >= 1) { + + SERIAL_PROTOCOL(mesh_point); + clamped ? SERIAL_PROTOCOLPGM(": xy clamped.\n") : SERIAL_PROTOCOLPGM(": no xy clamping\n"); + } + + + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], XY_AXIS_FEEDRATE, active_extruder); + st_synchronize(); + + // Go down until endstop is hit + const float Z_CALIBRATION_THRESHOLD = 1.f; + if (!find_bed_induction_sensor_point_z((has_z && mesh_point > 0) ? z0 - Z_CALIBRATION_THRESHOLD : -10.f)) { //if we have data from z calibration max allowed difference is 1mm for each point, if we dont have data max difference is 10mm from initial point + kill_message = MSG_BED_LEVELING_FAILED_POINT_LOW; + break; + } + if (MESH_HOME_Z_SEARCH - current_position[Z_AXIS] < 0.1f) { + kill_message = MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED; + break; + } + if (has_z && fabs(z0 - current_position[Z_AXIS]) > Z_CALIBRATION_THRESHOLD) { //if we have data from z calibration, max. allowed difference is 1mm for each point + kill_message = MSG_BED_LEVELING_FAILED_POINT_HIGH; + break; + } + + if (verbosity_level >= 10) { + SERIAL_ECHOPGM("X: "); + MYSERIAL.print(current_position[X_AXIS], 5); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("Y: "); + MYSERIAL.print(current_position[Y_AXIS], 5); + SERIAL_PROTOCOLPGM("\n"); + } + + if (verbosity_level >= 1) { + SERIAL_ECHOPGM("mesh bed leveling: "); + MYSERIAL.print(current_position[Z_AXIS], 5); + SERIAL_ECHOLNPGM(""); + } + mbl.set_z(ix, iy, current_position[Z_AXIS]); //store measured z values z_values[iy][ix] = z; + + custom_message_state--; + mesh_point++; + lcd_update(1); + } + if (verbosity_level >= 20) SERIAL_ECHOLNPGM("Mesh bed leveling while loop finished."); + current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; + if (verbosity_level >= 20) { + SERIAL_ECHOLNPGM("MESH_HOME_Z_SEARCH: "); + MYSERIAL.print(current_position[Z_AXIS], 5); + } + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], Z_LIFT_FEEDRATE, active_extruder); + st_synchronize(); + if (mesh_point != MESH_MEAS_NUM_X_POINTS * MESH_MEAS_NUM_Y_POINTS) { + kill(kill_message); + SERIAL_ECHOLNPGM("killed"); + } + clean_up_after_endstop_move(); + SERIAL_ECHOLNPGM("clean up finished "); + if(temp_cal_active == true && calibration_status_pinda() == true) temp_compensation_apply(); //apply PINDA temperature compensation + babystep_apply(); // Apply Z height correction aka baby stepping before mesh bed leveing gets activated. + SERIAL_ECHOLNPGM("babystep applied"); + bool eeprom_bed_correction_valid = eeprom_read_byte((unsigned char*)EEPROM_BED_CORRECTION_VALID) == 1; + + if (verbosity_level >= 1) { + eeprom_bed_correction_valid ? SERIAL_PROTOCOLPGM("Bed correction data valid\n") : SERIAL_PROTOCOLPGM("Bed correction data not valid\n"); + } + + for (uint8_t i = 0; i < 4; ++i) { + unsigned char codes[4] = { 'L', 'R', 'F', 'B' }; + long correction = 0; + if (code_seen(codes[i])) + correction = code_value_long(); + else if (eeprom_bed_correction_valid) { + unsigned char *addr = (i < 2) ? + ((i == 0) ? (unsigned char*)EEPROM_BED_CORRECTION_LEFT : (unsigned char*)EEPROM_BED_CORRECTION_RIGHT) : + ((i == 2) ? (unsigned char*)EEPROM_BED_CORRECTION_FRONT : (unsigned char*)EEPROM_BED_CORRECTION_REAR); + correction = eeprom_read_int8(addr); + } + if (correction == 0) + continue; + float offset = float(correction) * 0.001f; + if (fabs(offset) > 0.101f) { + SERIAL_ERROR_START; + SERIAL_ECHOPGM("Excessive bed leveling correction: "); + SERIAL_ECHO(offset); + SERIAL_ECHOLNPGM(" microns"); + } + else { + switch (i) { + case 0: + for (uint8_t row = 0; row < 3; ++row) { + mbl.z_values[row][1] += 0.5f * offset; + mbl.z_values[row][0] += offset; + } + break; + case 1: + for (uint8_t row = 0; row < 3; ++row) { + mbl.z_values[row][1] += 0.5f * offset; + mbl.z_values[row][2] += offset; + } + break; + case 2: + for (uint8_t col = 0; col < 3; ++col) { + mbl.z_values[1][col] += 0.5f * offset; + mbl.z_values[0][col] += offset; + } + break; + case 3: + for (uint8_t col = 0; col < 3; ++col) { + mbl.z_values[1][col] += 0.5f * offset; + mbl.z_values[2][col] += offset; + } + break; + } + } + } + SERIAL_ECHOLNPGM("Bed leveling correction finished"); + mbl.upsample_3x3(); //bilinear interpolation from 3x3 to 7x7 points while using the same array z_values[iy][ix] for storing (just coppying measured data to new destination and interpolating between them) + SERIAL_ECHOLNPGM("Upsample finished"); + mbl.active = 1; //activate mesh bed leveling + SERIAL_ECHOLNPGM("Mesh bed leveling activated"); + go_home_with_z_lift(); + SERIAL_ECHOLNPGM("Go home finished"); + //unretract (after PINDA preheat retraction) + if (degHotend(active_extruder) > EXTRUDE_MINTEMP && temp_cal_active == true && calibration_status_pinda() == true && target_temperature_bed >= 50) { + current_position[E_AXIS] += DEFAULT_RETRACTION; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 400, active_extruder); + } + // Restore custom message state + custom_message = custom_message_old; + custom_message_type = custom_message_type_old; + custom_message_state = custom_message_state_old; + mesh_bed_leveling_flag = false; + mesh_bed_run_from_menu = false; + lcd_update(2); + + } + break; /** * G81: Print mesh bed leveling status and bed profile if activated @@ -3150,7 +3305,7 @@ void process_commands() * This G-code will be performed at the end of a calibration script. */ case 87: - calibration_status_store(CALIBRATION_STATUS_CALIBRATED); + calibration_status_store(CALIBRATION_STATUS_CALIBRATED); break; /** @@ -3522,14 +3677,15 @@ void process_commands() calibration_status_store(CALIBRATION_STATUS_ASSEMBLED); eeprom_update_word((uint16_t*)EEPROM_BABYSTEP_Z, 0); // Complete XYZ calibration. - BedSkewOffsetDetectionResultType result = find_bed_offset_and_skew(verbosity_level); - uint8_t point_too_far_mask = 0; - clean_up_after_endstop_move(); + uint8_t point_too_far_mask = 0; + BedSkewOffsetDetectionResultType result = find_bed_offset_and_skew(verbosity_level, point_too_far_mask); + clean_up_after_endstop_move(); // Print head up. current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS],current_position[Z_AXIS] , current_position[E_AXIS], homing_feedrate[Z_AXIS]/40, active_extruder); st_synchronize(); if (result >= 0) { + point_too_far_mask = 0; // Second half: The fine adjustment. // Let the planner use the uncorrected coordinates. mbl.reset(); @@ -3936,11 +4092,18 @@ Sigma_Exit: #endif #ifdef SHOW_TEMP_ADC_VALUES + {float raw = 0.0; + #if defined(TEMP_BED_PIN) && TEMP_BED_PIN > -1 SERIAL_PROTOCOLPGM(" ADC B:"); SERIAL_PROTOCOL_F(degBed(),1); SERIAL_PROTOCOLPGM("C->"); - SERIAL_PROTOCOL_F(rawBedTemp()/OVERSAMPLENR,0); + raw = rawBedTemp(); + SERIAL_PROTOCOL_F(raw/OVERSAMPLENR,5); + SERIAL_PROTOCOLPGM(" Rb->"); + SERIAL_PROTOCOL_F(100 * (1 + (PtA * (raw/OVERSAMPLENR)) + (PtB * sq((raw/OVERSAMPLENR)))), 5); + SERIAL_PROTOCOLPGM(" Rxb->"); + SERIAL_PROTOCOL_F(raw, 5); #endif for (int8_t cur_extruder = 0; cur_extruder < EXTRUDERS; ++cur_extruder) { SERIAL_PROTOCOLPGM(" T"); @@ -3948,8 +4111,17 @@ Sigma_Exit: SERIAL_PROTOCOLPGM(":"); SERIAL_PROTOCOL_F(degHotend(cur_extruder),1); SERIAL_PROTOCOLPGM("C->"); - SERIAL_PROTOCOL_F(rawHotendTemp(cur_extruder)/OVERSAMPLENR,0); - } + raw = rawHotendTemp(cur_extruder); + SERIAL_PROTOCOL_F(raw/OVERSAMPLENR,5); + SERIAL_PROTOCOLPGM(" Rt"); + SERIAL_PROTOCOL(cur_extruder); + SERIAL_PROTOCOLPGM("->"); + SERIAL_PROTOCOL_F(100 * (1 + (PtA * (raw/OVERSAMPLENR)) + (PtB * sq((raw/OVERSAMPLENR)))), 5); + SERIAL_PROTOCOLPGM(" Rx"); + SERIAL_PROTOCOL(cur_extruder); + SERIAL_PROTOCOLPGM("->"); + SERIAL_PROTOCOL_F(raw, 5); + }} #endif SERIAL_PROTOCOLLN(""); return; @@ -3991,60 +4163,13 @@ Sigma_Exit: cancel_heatup = false; - #ifdef TEMP_RESIDENCY_TIME - long residencyStart; - residencyStart = -1; - /* continue to loop until we have reached the target temp - _and_ until TEMP_RESIDENCY_TIME hasn't passed since we reached it */ - while((!cancel_heatup)&&((residencyStart == -1) || - (residencyStart >= 0 && (((unsigned int) (millis() - residencyStart)) < (TEMP_RESIDENCY_TIME * 1000UL)))) ) { - #else - while ( target_direction ? (isHeatingHotend(tmp_extruder)) : (isCoolingHotend(tmp_extruder)&&(CooldownNoWait==false)) ) { - #endif //TEMP_RESIDENCY_TIME - if( (millis() - codenum) > 1000UL ) - { //Print Temp Reading and remaining time every 1 second while heating up/cooling down - if (!farm_mode) { - SERIAL_PROTOCOLPGM("T:"); - SERIAL_PROTOCOL_F(degHotend(tmp_extruder), 1); - SERIAL_PROTOCOLPGM(" E:"); - SERIAL_PROTOCOL((int)tmp_extruder); + wait_for_heater(codenum); //loops until target temperature is reached - #ifdef TEMP_RESIDENCY_TIME - SERIAL_PROTOCOLPGM(" W:"); - if (residencyStart > -1) - { - codenum = ((TEMP_RESIDENCY_TIME * 1000UL) - (millis() - residencyStart)) / 1000UL; - SERIAL_PROTOCOLLN(codenum); - } - else - { - SERIAL_PROTOCOLLN("?"); - } - } - #else - SERIAL_PROTOCOLLN(""); - #endif - codenum = millis(); - } - manage_heater(); - manage_inactivity(); - lcd_update(); - #ifdef TEMP_RESIDENCY_TIME - /* start/restart the TEMP_RESIDENCY_TIME timer whenever we reach target temp for the first time - or when current temp falls outside the hysteresis after target temp was reached */ - if ((residencyStart == -1 && target_direction && (degHotend(tmp_extruder) >= (degTargetHotend(tmp_extruder)-TEMP_WINDOW))) || - (residencyStart == -1 && !target_direction && (degHotend(tmp_extruder) <= (degTargetHotend(tmp_extruder)+TEMP_WINDOW))) || - (residencyStart > -1 && labs(degHotend(tmp_extruder) - degTargetHotend(tmp_extruder)) > TEMP_HYSTERESIS) ) - { - residencyStart = millis(); - } - #endif //TEMP_RESIDENCY_TIME - } LCD_MESSAGERPGM(MSG_HEATING_COMPLETE); heating_status = 2; if (farm_mode) { prusa_statistics(2); }; - starttime=millis(); + //starttime=millis(); previous_millis_cmd = millis(); } break; @@ -4187,18 +4312,19 @@ Sigma_Exit: else { st_synchronize(); - if(code_seen('X')) disable_x(); - if(code_seen('Y')) disable_y(); - if(code_seen('Z')) disable_z(); - #if ((E0_ENABLE_PIN != X_ENABLE_PIN) && (E1_ENABLE_PIN != Y_ENABLE_PIN)) // Only enable on boards that have seperate ENABLE_PINS - if(code_seen('E')) { - disable_e0(); - disable_e1(); - disable_e2(); + if (code_seen('X')) disable_x(); + if (code_seen('Y')) disable_y(); + if (code_seen('Z')) disable_z(); +#if ((E0_ENABLE_PIN != X_ENABLE_PIN) && (E1_ENABLE_PIN != Y_ENABLE_PIN)) // Only enable on boards that have seperate ENABLE_PINS + if (code_seen('E')) { + disable_e0(); + disable_e1(); + disable_e2(); } #endif } } + snmm_filaments_used = 0; break; case 85: // M85 if(code_seen('S')) { @@ -4238,12 +4364,12 @@ Sigma_Exit: SERIAL_PROTOCOLRPGM(MSG_M115_REPORT); } break; - case 117: // M117 display message +/* case 117: // M117 display message starpos = (strchr(strchr_pointer + 5,'*')); if(starpos!=NULL) *(starpos)='\0'; lcd_setstatus(strchr_pointer + 5); - break; + break;*/ case 114: // M114 SERIAL_PROTOCOLPGM("X:"); SERIAL_PROTOCOL(current_position[X_AXIS]); @@ -4349,7 +4475,7 @@ Sigma_Exit: tmp_extruder = active_extruder; if(code_seen('T')) { tmp_extruder = code_value(); - if(tmp_extruder >= EXTRUDERS) { + if(tmp_extruder >= EXTRUDERS) { SERIAL_ECHO_START; SERIAL_ECHO(MSG_M200_INVALID_EXTRUDER); break; @@ -4919,7 +5045,10 @@ case 404: //M404 Enter the nominal filament width (3mm, 1.75mm ) N<3.0> or disp #ifdef FILAMENTCHANGEENABLE case 600: //Pause for filament change X[pos] Y[pos] Z[relative lift] E[initial retract] L[later retract distance for removal] { + st_synchronize(); + float target[4]; + float lastpos[4]; if (farm_mode) @@ -4931,8 +5060,7 @@ case 404: //M404 Enter the nominal filament width (3mm, 1.75mm ) N<3.0> or disp feedmultiplyBckp=feedmultiply; int8_t TooLowZ = 0; - float target[4]; - float lastpos[4]; + target[X_AXIS]=current_position[X_AXIS]; target[Y_AXIS]=current_position[Y_AXIS]; target[Z_AXIS]=current_position[Z_AXIS]; @@ -4998,6 +5126,9 @@ case 404: //M404 Enter the nominal filament width (3mm, 1.75mm ) N<3.0> or disp #endif } plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], FILAMENTCHANGE_XYFEED, active_extruder); + st_synchronize(); + custom_message = true; + lcd_setstatuspgm(MSG_UNLOADING_FILAMENT); // Unload filament if(code_seen('L')) @@ -5006,11 +5137,35 @@ case 404: //M404 Enter the nominal filament width (3mm, 1.75mm ) N<3.0> or disp } else { - #ifdef FILAMENTCHANGE_FINALRETRACT - target[E_AXIS]+= FILAMENTCHANGE_FINALRETRACT ; - #endif + #ifdef SNMM + + #else + #ifdef FILAMENTCHANGE_FINALRETRACT + target[E_AXIS] += FILAMENTCHANGE_FINALRETRACT; + #endif + #endif // SNMM } - plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], FILAMENTCHANGE_RFEED, active_extruder); + +#ifdef SNMM + target[E_AXIS] += 12; + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 3500, active_extruder); + target[E_AXIS] += 6; + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 5000, active_extruder); + target[E_AXIS] += (FIL_LOAD_LENGTH * -1); + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 5000, active_extruder); + st_synchronize(); + target[E_AXIS] += (FIL_COOLING); + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 50, active_extruder); + target[E_AXIS] += (FIL_COOLING*-1); + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 50, active_extruder); + target[E_AXIS] += (bowden_length[snmm_extruder] *-1); + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 3000, active_extruder); + st_synchronize(); + +#else + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], FILAMENTCHANGE_RFEED, active_extruder); +#endif // SNMM + //finish moves st_synchronize(); @@ -5024,10 +5179,19 @@ case 404: //M404 Enter the nominal filament width (3mm, 1.75mm ) N<3.0> or disp uint8_t cnt=0; int counterBeep = 0; lcd_wait_interact(); + load_filament_time = millis(); while(!lcd_clicked()){ - cnt++; + + cnt++; manage_heater(); manage_inactivity(true); + +/*#ifdef SNMM + target[E_AXIS] += 0.002; + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 500, active_extruder); + +#endif // SNMM*/ + if(cnt==0) { #if BEEPER > 0 @@ -5037,7 +5201,7 @@ case 404: //M404 Enter the nominal filament width (3mm, 1.75mm ) N<3.0> or disp SET_OUTPUT(BEEPER); if (counterBeep== 0){ WRITE(BEEPER,HIGH); - } + } if (counterBeep== 20){ WRITE(BEEPER,LOW); } @@ -5050,21 +5214,48 @@ case 404: //M404 Enter the nominal filament width (3mm, 1.75mm ) N<3.0> or disp #endif #endif } + } +#ifdef SNMM + display_loading(); + do { + target[E_AXIS] += 0.002; + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 500, active_extruder); + delay_keep_alive(2); + } while (!lcd_clicked()); + /*if (millis() - load_filament_time > 2) { + load_filament_time = millis(); + target[E_AXIS] += 0.001; + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 1000, active_extruder); + }*/ +#endif //Filament inserted WRITE(BEEPER,LOW); - - //Feed the filament to the end of nozzle quickly - target[E_AXIS]+= FILAMENTCHANGE_FIRSTFEED ; - plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], FILAMENTCHANGE_EFEED, active_extruder); + + //Feed the filament to the end of nozzle quickly +#ifdef SNMM + + st_synchronize(); + target[E_AXIS] += bowden_length[snmm_extruder]; + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 3000, active_extruder); + target[E_AXIS] += FIL_LOAD_LENGTH - 60; + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 1400, active_extruder); + target[E_AXIS] += 40; + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 400, active_extruder); + target[E_AXIS] += 10; + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 50, active_extruder); +#else + target[E_AXIS] += FILAMENTCHANGE_FIRSTFEED; + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], FILAMENTCHANGE_EFEED, active_extruder); +#endif // SNMM //Extrude some filament target[E_AXIS]+= FILAMENTCHANGE_FINALFEED ; plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], FILAMENTCHANGE_EXFEED, active_extruder); - + //Wait for user to check the state lcd_change_fil_state = 0; @@ -5076,13 +5267,33 @@ case 404: //M404 Enter the nominal filament width (3mm, 1.75mm ) N<3.0> or disp // Filament failed to load so load it again case 2: +#ifdef SNMM + display_loading(); + do { + target[E_AXIS] += 0.002; + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 500, active_extruder); + delay_keep_alive(2); + } while (!lcd_clicked()); + + st_synchronize(); + target[E_AXIS] += bowden_length[snmm_extruder]; + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 3000, active_extruder); + target[E_AXIS] += FIL_LOAD_LENGTH - 60; + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 1400, active_extruder); + target[E_AXIS] += 40; + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 400, active_extruder); + target[E_AXIS] += 10; + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 50, active_extruder); + +#else target[E_AXIS]+= FILAMENTCHANGE_FIRSTFEED ; plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], FILAMENTCHANGE_EFEED, active_extruder); - +#endif target[E_AXIS]+= FILAMENTCHANGE_FINALFEED ; plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], FILAMENTCHANGE_EXFEED, active_extruder); lcd_loading_filament(); + break; // Filament loaded properly but color is not clear @@ -5095,6 +5306,7 @@ case 404: //M404 Enter the nominal filament width (3mm, 1.75mm ) N<3.0> or disp // Everything good default: lcd_change_success(); + lcd_update_enable(true); break; } @@ -5135,11 +5347,23 @@ case 404: //M404 Enter the nominal filament width (3mm, 1.75mm ) N<3.0> or disp char cmd[9]; sprintf_P(cmd, PSTR("M220 S%i"), feedmultiplyBckp); enquecommand(cmd); - + + lcd_setstatuspgm(WELCOME_MSG); + custom_message = false; + custom_message_type = 0; } break; #endif //FILAMENTCHANGEENABLE + case 601: { + if(lcd_commands_type == 0) lcd_commands_type = LCD_COMMAND_LONG_PAUSE; + } + break; + + case 602: { + if(lcd_commands_type == 0) lcd_commands_type = LCD_COMMAND_LONG_PAUSE_RESUME; + } + break; case 907: // M907 Set digital trimpot motor current using axis codes. { @@ -5210,10 +5434,10 @@ case 404: //M404 Enter the nominal filament width (3mm, 1.75mm ) N<3.0> or disp custom_message_type = 2; lcd_setstatuspgm(MSG_LOADING_FILAMENT); - current_position[E_AXIS] += 65; + current_position[E_AXIS] += 70; plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 400 / 60, active_extruder); //fast sequence - current_position[E_AXIS] += 40; + current_position[E_AXIS] += 25; plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 100 / 60, active_extruder); //slow sequence st_synchronize(); @@ -5223,7 +5447,7 @@ case 404: //M404 Enter the nominal filament width (3mm, 1.75mm ) N<3.0> or disp while (!clean) { lcd_update_enable(true); lcd_update(2); - current_position[E_AXIS] += 40; + current_position[E_AXIS] += 25; plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 100 / 60, active_extruder); //slow sequence st_synchronize(); clean = lcd_show_fullscreen_message_yes_no_and_wait_P(MSG_FILAMENT_CLEAN, false, true); @@ -5240,17 +5464,27 @@ case 404: //M404 Enter the nominal filament width (3mm, 1.75mm ) N<3.0> or disp break; case 702: { +#ifdef SNMM + if (code_seen('U')) { + extr_unload_used(); //unload all filaments which were used in current print + } + else if (code_seen('C')) { + extr_unload(); //unload just current filament + } + else { + extr_unload_all(); //unload all filaments + } +#else custom_message = true; custom_message_type = 2; lcd_setstatuspgm(MSG_UNLOADING_FILAMENT); - current_position[E_AXIS] -= 80; plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 7000 / 60, active_extruder); st_synchronize(); lcd_setstatuspgm(WELCOME_MSG); custom_message = false; custom_message_type = 0; - +#endif } break; @@ -5270,12 +5504,19 @@ case 404: //M404 Enter the nominal filament width (3mm, 1.75mm ) N<3.0> or disp int index; for (index = 1; *(strchr_pointer + index) == ' ' || *(strchr_pointer + index) == '\t'; index++); - if (*(strchr_pointer + index) < '0' || *(strchr_pointer + index) > '9') { + if ((*(strchr_pointer + index) < '0' || *(strchr_pointer + index) > '9') && *(strchr_pointer + index) != '?') { SERIAL_ECHOLNPGM("Invalid T code."); } else { - tmp_extruder = code_value(); + if (*(strchr_pointer + index) == '?') { + tmp_extruder = choose_extruder_menu(); + } + else { + tmp_extruder = code_value(); + } + snmm_filaments_used |= (1 << tmp_extruder); //for stop print #ifdef SNMM + snmm_extruder = tmp_extruder; st_synchronize(); delay(100); @@ -5887,7 +6128,7 @@ void calculate_volumetric_multipliers() { #endif } -void delay_keep_alive(int ms) +void delay_keep_alive(unsigned int ms) { for (;;) { manage_heater(); @@ -5906,6 +6147,59 @@ void delay_keep_alive(int ms) } } +void wait_for_heater(long codenum) { + +#ifdef TEMP_RESIDENCY_TIME + long residencyStart; + residencyStart = -1; + /* continue to loop until we have reached the target temp + _and_ until TEMP_RESIDENCY_TIME hasn't passed since we reached it */ + while ((!cancel_heatup) && ((residencyStart == -1) || + (residencyStart >= 0 && (((unsigned int)(millis() - residencyStart)) < (TEMP_RESIDENCY_TIME * 1000UL))))) { +#else + while (target_direction ? (isHeatingHotend(tmp_extruder)) : (isCoolingHotend(tmp_extruder) && (CooldownNoWait == false))) { +#endif //TEMP_RESIDENCY_TIME + if ((millis() - codenum) > 1000UL) + { //Print Temp Reading and remaining time every 1 second while heating up/cooling down + if (!farm_mode) { + SERIAL_PROTOCOLPGM("T:"); + SERIAL_PROTOCOL_F(degHotend(tmp_extruder), 1); + SERIAL_PROTOCOLPGM(" E:"); + SERIAL_PROTOCOL((int)tmp_extruder); + +#ifdef TEMP_RESIDENCY_TIME + SERIAL_PROTOCOLPGM(" W:"); + if (residencyStart > -1) + { + codenum = ((TEMP_RESIDENCY_TIME * 1000UL) - (millis() - residencyStart)) / 1000UL; + SERIAL_PROTOCOLLN(codenum); + } + else + { + SERIAL_PROTOCOLLN("?"); + } + } +#else + SERIAL_PROTOCOLLN(""); +#endif + codenum = millis(); + } + manage_heater(); + manage_inactivity(); + lcd_update(); +#ifdef TEMP_RESIDENCY_TIME + /* start/restart the TEMP_RESIDENCY_TIME timer whenever we reach target temp for the first time + or when current temp falls outside the hysteresis after target temp was reached */ + if ((residencyStart == -1 && target_direction && (degHotend(tmp_extruder) >= (degTargetHotend(tmp_extruder) - TEMP_WINDOW))) || + (residencyStart == -1 && !target_direction && (degHotend(tmp_extruder) <= (degTargetHotend(tmp_extruder) + TEMP_WINDOW))) || + (residencyStart > -1 && labs(degHotend(tmp_extruder) - degTargetHotend(tmp_extruder)) > TEMP_HYSTERESIS)) + { + residencyStart = millis(); + } +#endif //TEMP_RESIDENCY_TIME + } +} + void check_babystep() { int babystep_z; EEPROM_read_B(EEPROM_BABYSTEP_Z, &babystep_z); @@ -6153,5 +6447,175 @@ void bed_analysis(float x_dimension, float y_dimension, int x_points_num, int y_ card.closefile(); } - #endif + +void temp_compensation_start() { + + custom_message = true; + custom_message_type = 5; + custom_message_state = PINDA_HEAT_T + 1; + lcd_update(2); + if (degHotend(active_extruder) > EXTRUDE_MINTEMP) { + current_position[E_AXIS] -= DEFAULT_RETRACTION; + } + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 400, active_extruder); + + current_position[X_AXIS] = PINDA_PREHEAT_X; + current_position[Y_AXIS] = PINDA_PREHEAT_Y; + current_position[Z_AXIS] = PINDA_PREHEAT_Z; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); + st_synchronize(); + while (fabs(degBed() - target_temperature_bed) > 1) delay_keep_alive(1000); + + for (int i = 0; i < PINDA_HEAT_T; i++) { + delay_keep_alive(1000); + custom_message_state = PINDA_HEAT_T - i; + if (custom_message_state == 99 || custom_message_state == 9) lcd_update(2); //force whole display redraw if number of digits changed + else lcd_update(1); + } + custom_message_type = 0; + custom_message_state = 0; + custom_message = false; +} + +void temp_compensation_apply() { + int i_add; + int compensation_value; + int z_shift = 0; + float z_shift_mm; + + if (calibration_status() == CALIBRATION_STATUS_CALIBRATED) { + if (target_temperature_bed % 10 == 0 && target_temperature_bed >= 60 && target_temperature_bed <= 100) { + i_add = (target_temperature_bed - 60) / 10; + EEPROM_read_B(EEPROM_PROBE_TEMP_SHIFT + i_add * 2, &z_shift); + z_shift_mm = z_shift / axis_steps_per_unit[Z_AXIS]; + }else { + //interpolation + z_shift_mm = temp_comp_interpolation(target_temperature_bed) / axis_steps_per_unit[Z_AXIS]; + } + SERIAL_PROTOCOLPGM("\n"); + SERIAL_PROTOCOLPGM("Z shift applied:"); + MYSERIAL.print(z_shift_mm); + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] - z_shift_mm, current_position[E_AXIS], homing_feedrate[Z_AXIS] / 40, active_extruder); + st_synchronize(); + plan_set_z_position(current_position[Z_AXIS]); + } + else { + //we have no temp compensation data + } +} + +float temp_comp_interpolation(float inp_temperature) { + + //cubic spline interpolation + + int n, i, j, k; + float h[10], a, b, c, d, sum, s[10] = { 0 }, x[10], F[10], f[10], m[10][10] = { 0 }, temp; + int shift[10]; + int temp_C[10]; + + n = 6; //number of measured points + + shift[0] = 0; + for (i = 0; i < n; i++) { + if (i>0) EEPROM_read_B(EEPROM_PROBE_TEMP_SHIFT + (i-1) * 2, &shift[i]); //read shift in steps from EEPROM + temp_C[i] = 50 + i * 10; //temperature in C + + x[i] = (float)temp_C[i]; + f[i] = (float)shift[i]; + } + if (inp_temperature < x[0]) return 0; + + + for (i = n - 1; i>0; i--) { + F[i] = (f[i] - f[i - 1]) / (x[i] - x[i - 1]); + h[i - 1] = x[i] - x[i - 1]; + } + //*********** formation of h, s , f matrix ************** + for (i = 1; i0; i--) { + sum = 0; + for (j = i; j <= n - 2; j++) + sum += m[i][j] * s[j]; + s[i] = (m[i][n - 1] - sum) / m[i][i]; + } + + for (i = 0; i x[i + 1])) { + a = (s[i + 1] - s[i]) / (6 * h[i]); + b = s[i] / 2; + c = (f[i + 1] - f[i]) / h[i] - (2 * h[i] * s[i] + s[i + 1] * h[i]) / 6; + d = f[i]; + sum = a*pow((inp_temperature - x[i]), 3) + b*pow((inp_temperature - x[i]), 2) + c*(inp_temperature - x[i]) + d; + } + + return sum; + +} + +void long_pause() //long pause print +{ + st_synchronize(); + + //save currently set parameters to global variables + saved_feedmultiply = feedmultiply; + HotendTempBckp = degTargetHotend(active_extruder); + fanSpeedBckp = fanSpeed; + start_pause_print = millis(); + + + //save position + pause_lastpos[X_AXIS] = current_position[X_AXIS]; + pause_lastpos[Y_AXIS] = current_position[Y_AXIS]; + pause_lastpos[Z_AXIS] = current_position[Z_AXIS]; + pause_lastpos[E_AXIS] = current_position[E_AXIS]; + + //retract + current_position[E_AXIS] -= DEFAULT_RETRACTION; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 400, active_extruder); + + //lift z + current_position[Z_AXIS] += Z_PAUSE_LIFT; + if (current_position[Z_AXIS] > Z_MAX_POS) current_position[Z_AXIS] = Z_MAX_POS; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 15, active_extruder); + + //set nozzle target temperature to 0 + setTargetHotend(0, 0); + setTargetHotend(0, 1); + setTargetHotend(0, 2); + + //Move XY to side + current_position[X_AXIS] = X_PAUSE_POS; + current_position[Y_AXIS] = Y_PAUSE_POS; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 50, active_extruder); + + // Turn off the print fan + fanSpeed = 0; + + st_synchronize(); +} + +void serialecho_temperatures() { + float tt = degHotend(active_extruder); + SERIAL_PROTOCOLPGM("T:"); + SERIAL_PROTOCOL(tt); + SERIAL_PROTOCOLPGM(" E:"); + SERIAL_PROTOCOL((int)active_extruder); + SERIAL_PROTOCOLPGM(" B:"); + SERIAL_PROTOCOL_F(degBed(), 1); + SERIAL_PROTOCOLLN(""); +} \ No newline at end of file diff --git a/Firmware/Sd2Card.cpp b/Firmware/Sd2Card.cpp index 76f767485..0154ee03c 100644 --- a/Firmware/Sd2Card.cpp +++ b/Firmware/Sd2Card.cpp @@ -1,813 +1,813 @@ -/* Arduino Sd2Card Library - * Copyright (C) 2009 by William Greiman - * - * This file is part of the Arduino Sd2Card Library - * - * This Library is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This Library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the Arduino Sd2Card Library. If not, see - * . - */ -#include "Marlin.h" - -#ifdef SDSUPPORT -#include "Sd2Card.h" -//------------------------------------------------------------------------------ -#ifndef SOFTWARE_SPI -// functions for hardware SPI -//------------------------------------------------------------------------------ -// make sure SPCR rate is in expected bits -#if (SPR0 != 0 || SPR1 != 1) -#error unexpected SPCR bits -#endif -/** - * Initialize hardware SPI - * Set SCK rate to F_CPU/pow(2, 1 + spiRate) for spiRate [0,6] - */ -static void spiInit(uint8_t spiRate) { - // See avr processor documentation - SPCR = (1 << SPE) | (1 << MSTR) | (spiRate >> 1); - SPSR = spiRate & 1 || spiRate == 6 ? 0 : 1 << SPI2X; -} -//------------------------------------------------------------------------------ -/** SPI receive a byte */ -static uint8_t spiRec() { - SPDR = 0XFF; - while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ } - return SPDR; -} -//------------------------------------------------------------------------------ -/** SPI read data - only one call so force inline */ -static inline __attribute__((always_inline)) -void spiRead(uint8_t* buf, uint16_t nbyte) { - if (nbyte-- == 0) return; - SPDR = 0XFF; - for (uint16_t i = 0; i < nbyte; i++) { - while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ } - buf[i] = SPDR; - SPDR = 0XFF; - } - while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ } - buf[nbyte] = SPDR; -} -//------------------------------------------------------------------------------ -/** SPI send a byte */ -static void spiSend(uint8_t b) { - SPDR = b; - while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ } -} -//------------------------------------------------------------------------------ -/** SPI send block - only one call so force inline */ -static inline __attribute__((always_inline)) - void spiSendBlock(uint8_t token, const uint8_t* buf) { - SPDR = token; - for (uint16_t i = 0; i < 512; i += 2) { - while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ } - SPDR = buf[i]; - while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ } - SPDR = buf[i + 1]; - } - while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ } -} -//------------------------------------------------------------------------------ -#else // SOFTWARE_SPI -//------------------------------------------------------------------------------ -/** nop to tune soft SPI timing */ -#define nop asm volatile ("nop\n\t") -//------------------------------------------------------------------------------ -/** Soft SPI receive byte */ -static uint8_t spiRec() { - uint8_t data = 0; - // no interrupts during byte receive - about 8 us - cli(); - // output pin high - like sending 0XFF - fastDigitalWrite(SPI_MOSI_PIN, HIGH); - - for (uint8_t i = 0; i < 8; i++) { - fastDigitalWrite(SPI_SCK_PIN, HIGH); - - // adjust so SCK is nice - nop; - nop; - - data <<= 1; - - if (fastDigitalRead(SPI_MISO_PIN)) data |= 1; - - fastDigitalWrite(SPI_SCK_PIN, LOW); - } - // enable interrupts - sei(); - return data; -} -//------------------------------------------------------------------------------ -/** Soft SPI read data */ -static void spiRead(uint8_t* buf, uint16_t nbyte) { - for (uint16_t i = 0; i < nbyte; i++) { - buf[i] = spiRec(); - } -} -//------------------------------------------------------------------------------ -/** Soft SPI send byte */ -static void spiSend(uint8_t data) { - // no interrupts during byte send - about 8 us - cli(); - for (uint8_t i = 0; i < 8; i++) { - fastDigitalWrite(SPI_SCK_PIN, LOW); - - fastDigitalWrite(SPI_MOSI_PIN, data & 0X80); - - data <<= 1; - - fastDigitalWrite(SPI_SCK_PIN, HIGH); - } - // hold SCK high for a few ns - nop; - nop; - nop; - nop; - - fastDigitalWrite(SPI_SCK_PIN, LOW); - // enable interrupts - sei(); -} -//------------------------------------------------------------------------------ -/** Soft SPI send block */ - void spiSendBlock(uint8_t token, const uint8_t* buf) { - spiSend(token); - for (uint16_t i = 0; i < 512; i++) { - spiSend(buf[i]); - } -} -#endif // SOFTWARE_SPI -//------------------------------------------------------------------------------ -// send command and return error code. Return zero for OK -uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) { - // select card - chipSelectLow(); - - // wait up to 300 ms if busy - waitNotBusy(300); - - // send command - spiSend(cmd | 0x40); - - // send argument - for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s); - - // send CRC - uint8_t crc = 0XFF; - if (cmd == CMD0) crc = 0X95; // correct crc for CMD0 with arg 0 - if (cmd == CMD8) crc = 0X87; // correct crc for CMD8 with arg 0X1AA - spiSend(crc); - - // skip stuff byte for stop read - if (cmd == CMD12) spiRec(); - - // wait for response - for (uint8_t i = 0; ((status_ = spiRec()) & 0X80) && i != 0XFF; i++) { /* Intentionally left empty */ } - return status_; -} -//------------------------------------------------------------------------------ -/** - * Determine the size of an SD flash memory card. - * - * \return The number of 512 byte data blocks in the card - * or zero if an error occurs. - */ -uint32_t Sd2Card::cardSize() { - csd_t csd; - if (!readCSD(&csd)) return 0; - if (csd.v1.csd_ver == 0) { - uint8_t read_bl_len = csd.v1.read_bl_len; - uint16_t c_size = (csd.v1.c_size_high << 10) - | (csd.v1.c_size_mid << 2) | csd.v1.c_size_low; - uint8_t c_size_mult = (csd.v1.c_size_mult_high << 1) - | csd.v1.c_size_mult_low; - return (uint32_t)(c_size + 1) << (c_size_mult + read_bl_len - 7); - } else if (csd.v2.csd_ver == 1) { - uint32_t c_size = ((uint32_t)csd.v2.c_size_high << 16) - | (csd.v2.c_size_mid << 8) | csd.v2.c_size_low; - return (c_size + 1) << 10; - } else { - error(SD_CARD_ERROR_BAD_CSD); - return 0; - } -} -//------------------------------------------------------------------------------ -void Sd2Card::chipSelectHigh() { - digitalWrite(chipSelectPin_, HIGH); -} -//------------------------------------------------------------------------------ -void Sd2Card::chipSelectLow() { -#ifndef SOFTWARE_SPI - spiInit(spiRate_); -#endif // SOFTWARE_SPI - digitalWrite(chipSelectPin_, LOW); -} -//------------------------------------------------------------------------------ -/** Erase a range of blocks. - * - * \param[in] firstBlock The address of the first block in the range. - * \param[in] lastBlock The address of the last block in the range. - * - * \note This function requests the SD card to do a flash erase for a - * range of blocks. The data on the card after an erase operation is - * either 0 or 1, depends on the card vendor. The card must support - * single block erase. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - */ -bool Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) { - csd_t csd; - if (!readCSD(&csd)) goto fail; - // check for single block erase - if (!csd.v1.erase_blk_en) { - // erase size mask - uint8_t m = (csd.v1.sector_size_high << 1) | csd.v1.sector_size_low; - if ((firstBlock & m) != 0 || ((lastBlock + 1) & m) != 0) { - // error card can't erase specified area - error(SD_CARD_ERROR_ERASE_SINGLE_BLOCK); - goto fail; - } - } - if (type_ != SD_CARD_TYPE_SDHC) { - firstBlock <<= 9; - lastBlock <<= 9; - } - if (cardCommand(CMD32, firstBlock) - || cardCommand(CMD33, lastBlock) - || cardCommand(CMD38, 0)) { - error(SD_CARD_ERROR_ERASE); - goto fail; - } - if (!waitNotBusy(SD_ERASE_TIMEOUT)) { - error(SD_CARD_ERROR_ERASE_TIMEOUT); - goto fail; - } - chipSelectHigh(); - return true; - - fail: - chipSelectHigh(); - return false; -} -//------------------------------------------------------------------------------ -/** Determine if card supports single block erase. - * - * \return The value one, true, is returned if single block erase is supported. - * The value zero, false, is returned if single block erase is not supported. - */ -bool Sd2Card::eraseSingleBlockEnable() { - csd_t csd; - return readCSD(&csd) ? csd.v1.erase_blk_en : false; -} -//------------------------------------------------------------------------------ -/** - * Initialize an SD flash memory card. - * - * \param[in] sckRateID SPI clock rate selector. See setSckRate(). - * \param[in] chipSelectPin SD chip select pin number. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. The reason for failure - * can be determined by calling errorCode() and errorData(). - */ -bool Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) { - errorCode_ = type_ = 0; - chipSelectPin_ = chipSelectPin; - // 16-bit init start time allows over a minute - uint16_t t0 = (uint16_t)millis(); - uint32_t arg; - - // set pin modes - pinMode(chipSelectPin_, OUTPUT); - chipSelectHigh(); - pinMode(SPI_MISO_PIN, INPUT); - pinMode(SPI_MOSI_PIN, OUTPUT); - pinMode(SPI_SCK_PIN, OUTPUT); - -#ifndef SOFTWARE_SPI - // SS must be in output mode even it is not chip select - pinMode(SS_PIN, OUTPUT); - // set SS high - may be chip select for another SPI device -#if SET_SPI_SS_HIGH - digitalWrite(SS_PIN, HIGH); -#endif // SET_SPI_SS_HIGH - // set SCK rate for initialization commands - spiRate_ = SPI_SD_INIT_RATE; - spiInit(spiRate_); -#endif // SOFTWARE_SPI - - // must supply min of 74 clock cycles with CS high. - for (uint8_t i = 0; i < 10; i++) spiSend(0XFF); - - // command to go idle in SPI mode - while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) { - if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { - error(SD_CARD_ERROR_CMD0); - goto fail; - } - } - // check SD version - if ((cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND)) { - type(SD_CARD_TYPE_SD1); - } else { - // only need last byte of r7 response - for (uint8_t i = 0; i < 4; i++) status_ = spiRec(); - if (status_ != 0XAA) { - error(SD_CARD_ERROR_CMD8); - goto fail; - } - type(SD_CARD_TYPE_SD2); - } - // initialize card and send host supports SDHC if SD2 - arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0; - - while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) { - // check for timeout - if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { - error(SD_CARD_ERROR_ACMD41); - goto fail; - } - } - // if SD2 read OCR register to check for SDHC card - if (type() == SD_CARD_TYPE_SD2) { - if (cardCommand(CMD58, 0)) { - error(SD_CARD_ERROR_CMD58); - goto fail; - } - if ((spiRec() & 0XC0) == 0XC0) type(SD_CARD_TYPE_SDHC); - // discard rest of ocr - contains allowed voltage range - for (uint8_t i = 0; i < 3; i++) spiRec(); - } - chipSelectHigh(); - -#ifndef SOFTWARE_SPI - return setSckRate(sckRateID); -#else // SOFTWARE_SPI - return true; -#endif // SOFTWARE_SPI - - fail: - chipSelectHigh(); - return false; -} -//------------------------------------------------------------------------------ -/** - * Read a 512 byte block from an SD card. - * - * \param[in] blockNumber Logical block to be read. - * \param[out] dst Pointer to the location that will receive the data. - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - */ -bool Sd2Card::readBlock(uint32_t blockNumber, uint8_t* dst) { -#ifdef SD_CHECK_AND_RETRY - uint8_t retryCnt = 3; - // use address if not SDHC card - if (type()!= SD_CARD_TYPE_SDHC) blockNumber <<= 9; - retry2: - retryCnt --; - if (cardCommand(CMD17, blockNumber)) { - error(SD_CARD_ERROR_CMD17); - if (retryCnt > 0) goto retry; - goto fail; - } - if (!readData(dst, 512)) - { - if (retryCnt > 0) goto retry; - goto fail; - } - return true; - retry: - chipSelectHigh(); - cardCommand(CMD12, 0);//Try sending a stop command, but ignore the result. - errorCode_ = 0; - goto retry2; -#else - // use address if not SDHC card - if (type()!= SD_CARD_TYPE_SDHC) blockNumber <<= 9; - if (cardCommand(CMD17, blockNumber)) { - error(SD_CARD_ERROR_CMD17); - goto fail; - } - return readData(dst, 512); -#endif - - fail: - chipSelectHigh(); - return false; -} -//------------------------------------------------------------------------------ -/** Read one data block in a multiple block read sequence - * - * \param[in] dst Pointer to the location for the data to be read. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - */ -bool Sd2Card::readData(uint8_t *dst) { - chipSelectLow(); - return readData(dst, 512); -} - -#ifdef SD_CHECK_AND_RETRY -static const uint16_t crctab[] PROGMEM = { - 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, - 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, - 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, - 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, - 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, - 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, - 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, - 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, - 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, - 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, - 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, - 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, - 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, - 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, - 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, - 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, - 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, - 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, - 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, - 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, - 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, - 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, - 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, - 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, - 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, - 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, - 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, - 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, - 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, - 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, - 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, - 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 -}; -static uint16_t CRC_CCITT(const uint8_t* data, size_t n) { - uint16_t crc = 0; - for (size_t i = 0; i < n; i++) { - crc = pgm_read_word(&crctab[(crc >> 8 ^ data[i]) & 0XFF]) ^ (crc << 8); - } - return crc; -} -#endif - -//------------------------------------------------------------------------------ -bool Sd2Card::readData(uint8_t* dst, uint16_t count) { - // wait for start block token - uint16_t t0 = millis(); - while ((status_ = spiRec()) == 0XFF) { - if (((uint16_t)millis() - t0) > SD_READ_TIMEOUT) { - error(SD_CARD_ERROR_READ_TIMEOUT); - goto fail; - } - } - if (status_ != DATA_START_BLOCK) { - error(SD_CARD_ERROR_READ); - goto fail; - } - // transfer data - spiRead(dst, count); - -#ifdef SD_CHECK_AND_RETRY - { - uint16_t calcCrc = CRC_CCITT(dst, count); - uint16_t recvCrc = spiRec() << 8; - recvCrc |= spiRec(); - if (calcCrc != recvCrc) - { - error(SD_CARD_ERROR_CRC); - goto fail; - } - } -#else - // discard CRC - spiRec(); - spiRec(); -#endif - chipSelectHigh(); - // Toshiba FlashAir Patch. Purge pending status byte. - if (flash_air_compatible_) - spiSend(0XFF); - return true; - - fail: - chipSelectHigh(); - // Toshiba FlashAir Patch. Purge pending status byte. - if (flash_air_compatible_) - spiSend(0XFF); - return false; -} -//------------------------------------------------------------------------------ -/** read CID or CSR register */ -bool Sd2Card::readRegister(uint8_t cmd, void* buf) { - uint8_t* dst = reinterpret_cast(buf); - if (cardCommand(cmd, 0)) { - error(SD_CARD_ERROR_READ_REG); - goto fail; - } - return readData(dst, 16); - - fail: - chipSelectHigh(); - return false; -} -//------------------------------------------------------------------------------ -/** Start a read multiple blocks sequence. - * - * \param[in] blockNumber Address of first block in sequence. - * - * \note This function is used with readData() and readStop() for optimized - * multiple block reads. SPI chipSelect must be low for the entire sequence. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - */ -bool Sd2Card::readStart(uint32_t blockNumber) { - if (type()!= SD_CARD_TYPE_SDHC) blockNumber <<= 9; - if (cardCommand(CMD18, blockNumber)) { - error(SD_CARD_ERROR_CMD18); - goto fail; - } - chipSelectHigh(); - return true; - - fail: - chipSelectHigh(); - return false; -} -//------------------------------------------------------------------------------ -/** End a read multiple blocks sequence. - * -* \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - */ -bool Sd2Card::readStop() { - chipSelectLow(); - if (cardCommand(CMD12, 0)) { - error(SD_CARD_ERROR_CMD12); - goto fail; - } - chipSelectHigh(); - return true; - - fail: - chipSelectHigh(); - return false; -} -//------------------------------------------------------------------------------ -/** - * Set the SPI clock rate. - * - * \param[in] sckRateID A value in the range [0, 6]. - * - * The SPI clock will be set to F_CPU/pow(2, 1 + sckRateID). The maximum - * SPI rate is F_CPU/2 for \a sckRateID = 0 and the minimum rate is F_CPU/128 - * for \a scsRateID = 6. - * - * \return The value one, true, is returned for success and the value zero, - * false, is returned for an invalid value of \a sckRateID. - */ -bool Sd2Card::setSckRate(uint8_t sckRateID) { - if (sckRateID > 6) { - error(SD_CARD_ERROR_SCK_RATE); - return false; - } - spiRate_ = sckRateID; - return true; -} -//------------------------------------------------------------------------------ -// wait for card to go not busy -bool Sd2Card::waitNotBusy(uint16_t timeoutMillis) { - uint16_t t0 = millis(); - while (spiRec() != 0XFF) { - if (((uint16_t)millis() - t0) >= timeoutMillis) goto fail; - } - return true; - - fail: - return false; -} -//------------------------------------------------------------------------------ -/** - * Writes a 512 byte block to an SD card. - * - * \param[in] blockNumber Logical block to be written. - * \param[in] src Pointer to the location of the data to be written. - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - */ -bool Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) { - // use address if not SDHC card - if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; - if (cardCommand(CMD24, blockNumber)) { - error(SD_CARD_ERROR_CMD24); - goto fail; - } - if (!writeData(DATA_START_BLOCK, src)) goto fail; - - // wait for flash programming to complete - if (!waitNotBusy(SD_WRITE_TIMEOUT)) { - error(SD_CARD_ERROR_WRITE_TIMEOUT); - goto fail; - } - // response is r2 so get and check two bytes for nonzero - if (cardCommand(CMD13, 0) || spiRec()) { - error(SD_CARD_ERROR_WRITE_PROGRAMMING); - goto fail; - } - chipSelectHigh(); - return true; - - fail: - chipSelectHigh(); - return false; -} -//------------------------------------------------------------------------------ -/** Write one data block in a multiple block write sequence - * \param[in] src Pointer to the location of the data to be written. - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - */ -bool Sd2Card::writeData(const uint8_t* src) { - chipSelectLow(); - // wait for previous write to finish - if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail; - if (!writeData(WRITE_MULTIPLE_TOKEN, src)) goto fail; - chipSelectHigh(); - return true; - - fail: - error(SD_CARD_ERROR_WRITE_MULTIPLE); - chipSelectHigh(); - return false; -} -//------------------------------------------------------------------------------ -// send one block of data for write block or write multiple blocks -bool Sd2Card::writeData(uint8_t token, const uint8_t* src) { - spiSendBlock(token, src); - - spiSend(0xff); // dummy crc - spiSend(0xff); // dummy crc - - status_ = spiRec(); - if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) { - error(SD_CARD_ERROR_WRITE); - goto fail; - } - return true; - - fail: - chipSelectHigh(); - return false; -} -//------------------------------------------------------------------------------ -/** Start a write multiple blocks sequence. - * - * \param[in] blockNumber Address of first block in sequence. - * \param[in] eraseCount The number of blocks to be pre-erased. - * - * \note This function is used with writeData() and writeStop() - * for optimized multiple block writes. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - */ -bool Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) { - // send pre-erase count - if (cardAcmd(ACMD23, eraseCount)) { - error(SD_CARD_ERROR_ACMD23); - goto fail; - } - // use address if not SDHC card - if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; - if (cardCommand(CMD25, blockNumber)) { - error(SD_CARD_ERROR_CMD25); - goto fail; - } - chipSelectHigh(); - return true; - - fail: - chipSelectHigh(); - return false; -} -//------------------------------------------------------------------------------ -/** End a write multiple blocks sequence. - * -* \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - */ -bool Sd2Card::writeStop() { - chipSelectLow(); - if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail; - spiSend(STOP_TRAN_TOKEN); - if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail; - chipSelectHigh(); - return true; - - fail: - error(SD_CARD_ERROR_STOP_TRAN); - chipSelectHigh(); - return false; -} - -//------------------------------------------------------------------------------ -/** Wait for start block token */ -//FIXME Vojtech: Copied from a current version of Sd2Card Arduino code. -// We shall likely upgrade the rest of the Sd2Card. -uint8_t Sd2Card::waitStartBlock(void) { - uint16_t t0 = millis(); - while ((status_ = spiRec()) == 0XFF) { - if (((uint16_t)millis() - t0) > SD_READ_TIMEOUT) { - error(SD_CARD_ERROR_READ_TIMEOUT); - goto fail; - } - } - if (status_ != DATA_START_BLOCK) { - error(SD_CARD_ERROR_READ); - goto fail; - } - return true; - - fail: - chipSelectHigh(); - return false; -} - -// Toshiba FlashAir support, copied from -// https://flashair-developers.com/en/documents/tutorials/arduino/ - -//------------------------------------------------------------------------------ -/** Perform Extention Read. */ -uint8_t Sd2Card::readExt(uint32_t arg, uint8_t* dst, uint16_t count) { - uint16_t i; - - // send command and argument. - if (cardCommand(CMD48, arg)) { - error(SD_CARD_ERROR_CMD48); - goto fail; - } - - // wait for start block token. - if (!waitStartBlock()) { - goto fail; - } - - // receive data - for (i = 0; i < count; ++i) { - dst[i] = spiRec(); - } - - // skip dummy bytes and 16-bit crc. - for (; i < 514; ++i) { - spiRec(); - } - - chipSelectHigh(); - spiSend(0xFF); // dummy clock to force FlashAir finish the command. - return true; - - fail: - chipSelectHigh(); - return false; -} - -//------------------------------------------------------------------------------ -/** - * Read an extension register space. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - */ -uint8_t Sd2Card::readExtMemory(uint8_t mio, uint8_t func, - uint32_t addr, uint16_t count, uint8_t* dst) { - uint32_t offset = addr & 0x1FF; - if (offset + count > 512) count = 512 - offset; - - if (count == 0) return true; - - uint32_t arg = - (((uint32_t)mio & 0x1) << 31) | - (mio ? (((uint32_t)func & 0x7) << 28) : (((uint32_t)func & 0xF) << 27)) | - ((addr & 0x1FFFF) << 9) | - ((count - 1) & 0x1FF); - - return readExt(arg, dst, count); -} - -#endif +/* Arduino Sd2Card Library + * Copyright (C) 2009 by William Greiman + * + * This file is part of the Arduino Sd2Card Library + * + * This Library is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This Library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Arduino Sd2Card Library. If not, see + * . + */ +#include "Marlin.h" + +#ifdef SDSUPPORT +#include "Sd2Card.h" +//------------------------------------------------------------------------------ +#ifndef SOFTWARE_SPI +// functions for hardware SPI +//------------------------------------------------------------------------------ +// make sure SPCR rate is in expected bits +#if (SPR0 != 0 || SPR1 != 1) +#error unexpected SPCR bits +#endif +/** + * Initialize hardware SPI + * Set SCK rate to F_CPU/pow(2, 1 + spiRate) for spiRate [0,6] + */ +static void spiInit(uint8_t spiRate) { + // See avr processor documentation + SPCR = (1 << SPE) | (1 << MSTR) | (spiRate >> 1); + SPSR = spiRate & 1 || spiRate == 6 ? 0 : 1 << SPI2X; +} +//------------------------------------------------------------------------------ +/** SPI receive a byte */ +static uint8_t spiRec() { + SPDR = 0XFF; + while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ } + return SPDR; +} +//------------------------------------------------------------------------------ +/** SPI read data - only one call so force inline */ +static inline __attribute__((always_inline)) +void spiRead(uint8_t* buf, uint16_t nbyte) { + if (nbyte-- == 0) return; + SPDR = 0XFF; + for (uint16_t i = 0; i < nbyte; i++) { + while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ } + buf[i] = SPDR; + SPDR = 0XFF; + } + while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ } + buf[nbyte] = SPDR; +} +//------------------------------------------------------------------------------ +/** SPI send a byte */ +static void spiSend(uint8_t b) { + SPDR = b; + while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ } +} +//------------------------------------------------------------------------------ +/** SPI send block - only one call so force inline */ +static inline __attribute__((always_inline)) + void spiSendBlock(uint8_t token, const uint8_t* buf) { + SPDR = token; + for (uint16_t i = 0; i < 512; i += 2) { + while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ } + SPDR = buf[i]; + while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ } + SPDR = buf[i + 1]; + } + while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ } +} +//------------------------------------------------------------------------------ +#else // SOFTWARE_SPI +//------------------------------------------------------------------------------ +/** nop to tune soft SPI timing */ +#define nop asm volatile ("nop\n\t") +//------------------------------------------------------------------------------ +/** Soft SPI receive byte */ +static uint8_t spiRec() { + uint8_t data = 0; + // no interrupts during byte receive - about 8 us + cli(); + // output pin high - like sending 0XFF + fastDigitalWrite(SPI_MOSI_PIN, HIGH); + + for (uint8_t i = 0; i < 8; i++) { + fastDigitalWrite(SPI_SCK_PIN, HIGH); + + // adjust so SCK is nice + nop; + nop; + + data <<= 1; + + if (fastDigitalRead(SPI_MISO_PIN)) data |= 1; + + fastDigitalWrite(SPI_SCK_PIN, LOW); + } + // enable interrupts + sei(); + return data; +} +//------------------------------------------------------------------------------ +/** Soft SPI read data */ +static void spiRead(uint8_t* buf, uint16_t nbyte) { + for (uint16_t i = 0; i < nbyte; i++) { + buf[i] = spiRec(); + } +} +//------------------------------------------------------------------------------ +/** Soft SPI send byte */ +static void spiSend(uint8_t data) { + // no interrupts during byte send - about 8 us + cli(); + for (uint8_t i = 0; i < 8; i++) { + fastDigitalWrite(SPI_SCK_PIN, LOW); + + fastDigitalWrite(SPI_MOSI_PIN, data & 0X80); + + data <<= 1; + + fastDigitalWrite(SPI_SCK_PIN, HIGH); + } + // hold SCK high for a few ns + nop; + nop; + nop; + nop; + + fastDigitalWrite(SPI_SCK_PIN, LOW); + // enable interrupts + sei(); +} +//------------------------------------------------------------------------------ +/** Soft SPI send block */ + void spiSendBlock(uint8_t token, const uint8_t* buf) { + spiSend(token); + for (uint16_t i = 0; i < 512; i++) { + spiSend(buf[i]); + } +} +#endif // SOFTWARE_SPI +//------------------------------------------------------------------------------ +// send command and return error code. Return zero for OK +uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) { + // select card + chipSelectLow(); + + // wait up to 300 ms if busy + waitNotBusy(300); + + // send command + spiSend(cmd | 0x40); + + // send argument + for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s); + + // send CRC + uint8_t crc = 0XFF; + if (cmd == CMD0) crc = 0X95; // correct crc for CMD0 with arg 0 + if (cmd == CMD8) crc = 0X87; // correct crc for CMD8 with arg 0X1AA + spiSend(crc); + + // skip stuff byte for stop read + if (cmd == CMD12) spiRec(); + + // wait for response + for (uint8_t i = 0; ((status_ = spiRec()) & 0X80) && i != 0XFF; i++) { /* Intentionally left empty */ } + return status_; +} +//------------------------------------------------------------------------------ +/** + * Determine the size of an SD flash memory card. + * + * \return The number of 512 byte data blocks in the card + * or zero if an error occurs. + */ +uint32_t Sd2Card::cardSize() { + csd_t csd; + if (!readCSD(&csd)) return 0; + if (csd.v1.csd_ver == 0) { + uint8_t read_bl_len = csd.v1.read_bl_len; + uint16_t c_size = (csd.v1.c_size_high << 10) + | (csd.v1.c_size_mid << 2) | csd.v1.c_size_low; + uint8_t c_size_mult = (csd.v1.c_size_mult_high << 1) + | csd.v1.c_size_mult_low; + return (uint32_t)(c_size + 1) << (c_size_mult + read_bl_len - 7); + } else if (csd.v2.csd_ver == 1) { + uint32_t c_size = ((uint32_t)csd.v2.c_size_high << 16) + | (csd.v2.c_size_mid << 8) | csd.v2.c_size_low; + return (c_size + 1) << 10; + } else { + error(SD_CARD_ERROR_BAD_CSD); + return 0; + } +} +//------------------------------------------------------------------------------ +void Sd2Card::chipSelectHigh() { + digitalWrite(chipSelectPin_, HIGH); +} +//------------------------------------------------------------------------------ +void Sd2Card::chipSelectLow() { +#ifndef SOFTWARE_SPI + spiInit(spiRate_); +#endif // SOFTWARE_SPI + digitalWrite(chipSelectPin_, LOW); +} +//------------------------------------------------------------------------------ +/** Erase a range of blocks. + * + * \param[in] firstBlock The address of the first block in the range. + * \param[in] lastBlock The address of the last block in the range. + * + * \note This function requests the SD card to do a flash erase for a + * range of blocks. The data on the card after an erase operation is + * either 0 or 1, depends on the card vendor. The card must support + * single block erase. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + */ +bool Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) { + csd_t csd; + if (!readCSD(&csd)) goto fail; + // check for single block erase + if (!csd.v1.erase_blk_en) { + // erase size mask + uint8_t m = (csd.v1.sector_size_high << 1) | csd.v1.sector_size_low; + if ((firstBlock & m) != 0 || ((lastBlock + 1) & m) != 0) { + // error card can't erase specified area + error(SD_CARD_ERROR_ERASE_SINGLE_BLOCK); + goto fail; + } + } + if (type_ != SD_CARD_TYPE_SDHC) { + firstBlock <<= 9; + lastBlock <<= 9; + } + if (cardCommand(CMD32, firstBlock) + || cardCommand(CMD33, lastBlock) + || cardCommand(CMD38, 0)) { + error(SD_CARD_ERROR_ERASE); + goto fail; + } + if (!waitNotBusy(SD_ERASE_TIMEOUT)) { + error(SD_CARD_ERROR_ERASE_TIMEOUT); + goto fail; + } + chipSelectHigh(); + return true; + + fail: + chipSelectHigh(); + return false; +} +//------------------------------------------------------------------------------ +/** Determine if card supports single block erase. + * + * \return The value one, true, is returned if single block erase is supported. + * The value zero, false, is returned if single block erase is not supported. + */ +bool Sd2Card::eraseSingleBlockEnable() { + csd_t csd; + return readCSD(&csd) ? csd.v1.erase_blk_en : false; +} +//------------------------------------------------------------------------------ +/** + * Initialize an SD flash memory card. + * + * \param[in] sckRateID SPI clock rate selector. See setSckRate(). + * \param[in] chipSelectPin SD chip select pin number. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. The reason for failure + * can be determined by calling errorCode() and errorData(). + */ +bool Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) { + errorCode_ = type_ = 0; + chipSelectPin_ = chipSelectPin; + // 16-bit init start time allows over a minute + uint16_t t0 = (uint16_t)millis(); + uint32_t arg; + + // set pin modes + pinMode(chipSelectPin_, OUTPUT); + chipSelectHigh(); + pinMode(SPI_MISO_PIN, INPUT); + pinMode(SPI_MOSI_PIN, OUTPUT); + pinMode(SPI_SCK_PIN, OUTPUT); + +#ifndef SOFTWARE_SPI + // SS must be in output mode even it is not chip select + pinMode(SS_PIN, OUTPUT); + // set SS high - may be chip select for another SPI device +#if SET_SPI_SS_HIGH + digitalWrite(SS_PIN, HIGH); +#endif // SET_SPI_SS_HIGH + // set SCK rate for initialization commands + spiRate_ = SPI_SD_INIT_RATE; + spiInit(spiRate_); +#endif // SOFTWARE_SPI + + // must supply min of 74 clock cycles with CS high. + for (uint8_t i = 0; i < 10; i++) spiSend(0XFF); + + // command to go idle in SPI mode + while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) { + if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { + error(SD_CARD_ERROR_CMD0); + goto fail; + } + } + // check SD version + if ((cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND)) { + type(SD_CARD_TYPE_SD1); + } else { + // only need last byte of r7 response + for (uint8_t i = 0; i < 4; i++) status_ = spiRec(); + if (status_ != 0XAA) { + error(SD_CARD_ERROR_CMD8); + goto fail; + } + type(SD_CARD_TYPE_SD2); + } + // initialize card and send host supports SDHC if SD2 + arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0; + + while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) { + // check for timeout + if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { + error(SD_CARD_ERROR_ACMD41); + goto fail; + } + } + // if SD2 read OCR register to check for SDHC card + if (type() == SD_CARD_TYPE_SD2) { + if (cardCommand(CMD58, 0)) { + error(SD_CARD_ERROR_CMD58); + goto fail; + } + if ((spiRec() & 0XC0) == 0XC0) type(SD_CARD_TYPE_SDHC); + // discard rest of ocr - contains allowed voltage range + for (uint8_t i = 0; i < 3; i++) spiRec(); + } + chipSelectHigh(); + +#ifndef SOFTWARE_SPI + return setSckRate(sckRateID); +#else // SOFTWARE_SPI + return true; +#endif // SOFTWARE_SPI + + fail: + chipSelectHigh(); + return false; +} +//------------------------------------------------------------------------------ +/** + * Read a 512 byte block from an SD card. + * + * \param[in] blockNumber Logical block to be read. + * \param[out] dst Pointer to the location that will receive the data. + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + */ +bool Sd2Card::readBlock(uint32_t blockNumber, uint8_t* dst) { +#ifdef SD_CHECK_AND_RETRY + uint8_t retryCnt = 3; + // use address if not SDHC card + if (type()!= SD_CARD_TYPE_SDHC) blockNumber <<= 9; + retry2: + retryCnt --; + if (cardCommand(CMD17, blockNumber)) { + error(SD_CARD_ERROR_CMD17); + if (retryCnt > 0) goto retry; + goto fail; + } + if (!readData(dst, 512)) + { + if (retryCnt > 0) goto retry; + goto fail; + } + return true; + retry: + chipSelectHigh(); + cardCommand(CMD12, 0);//Try sending a stop command, but ignore the result. + errorCode_ = 0; + goto retry2; +#else + // use address if not SDHC card + if (type()!= SD_CARD_TYPE_SDHC) blockNumber <<= 9; + if (cardCommand(CMD17, blockNumber)) { + error(SD_CARD_ERROR_CMD17); + goto fail; + } + return readData(dst, 512); +#endif + + fail: + chipSelectHigh(); + return false; +} +//------------------------------------------------------------------------------ +/** Read one data block in a multiple block read sequence + * + * \param[in] dst Pointer to the location for the data to be read. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + */ +bool Sd2Card::readData(uint8_t *dst) { + chipSelectLow(); + return readData(dst, 512); +} + +#ifdef SD_CHECK_AND_RETRY +static const uint16_t crctab[] PROGMEM = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, + 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, + 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, + 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, + 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, + 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, + 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, + 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, + 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, + 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, + 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, + 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, + 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, + 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, + 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, + 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, + 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, + 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, + 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, + 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, + 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, + 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, + 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 +}; +static uint16_t CRC_CCITT(const uint8_t* data, size_t n) { + uint16_t crc = 0; + for (size_t i = 0; i < n; i++) { + crc = pgm_read_word(&crctab[(crc >> 8 ^ data[i]) & 0XFF]) ^ (crc << 8); + } + return crc; +} +#endif + +//------------------------------------------------------------------------------ +bool Sd2Card::readData(uint8_t* dst, uint16_t count) { + // wait for start block token + uint16_t t0 = millis(); + while ((status_ = spiRec()) == 0XFF) { + if (((uint16_t)millis() - t0) > SD_READ_TIMEOUT) { + error(SD_CARD_ERROR_READ_TIMEOUT); + goto fail; + } + } + if (status_ != DATA_START_BLOCK) { + error(SD_CARD_ERROR_READ); + goto fail; + } + // transfer data + spiRead(dst, count); + +#ifdef SD_CHECK_AND_RETRY + { + uint16_t calcCrc = CRC_CCITT(dst, count); + uint16_t recvCrc = spiRec() << 8; + recvCrc |= spiRec(); + if (calcCrc != recvCrc) + { + error(SD_CARD_ERROR_CRC); + goto fail; + } + } +#else + // discard CRC + spiRec(); + spiRec(); +#endif + chipSelectHigh(); + // Toshiba FlashAir Patch. Purge pending status byte. + if (flash_air_compatible_) + spiSend(0XFF); + return true; + + fail: + chipSelectHigh(); + // Toshiba FlashAir Patch. Purge pending status byte. + if (flash_air_compatible_) + spiSend(0XFF); + return false; +} +//------------------------------------------------------------------------------ +/** read CID or CSR register */ +bool Sd2Card::readRegister(uint8_t cmd, void* buf) { + uint8_t* dst = reinterpret_cast(buf); + if (cardCommand(cmd, 0)) { + error(SD_CARD_ERROR_READ_REG); + goto fail; + } + return readData(dst, 16); + + fail: + chipSelectHigh(); + return false; +} +//------------------------------------------------------------------------------ +/** Start a read multiple blocks sequence. + * + * \param[in] blockNumber Address of first block in sequence. + * + * \note This function is used with readData() and readStop() for optimized + * multiple block reads. SPI chipSelect must be low for the entire sequence. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + */ +bool Sd2Card::readStart(uint32_t blockNumber) { + if (type()!= SD_CARD_TYPE_SDHC) blockNumber <<= 9; + if (cardCommand(CMD18, blockNumber)) { + error(SD_CARD_ERROR_CMD18); + goto fail; + } + chipSelectHigh(); + return true; + + fail: + chipSelectHigh(); + return false; +} +//------------------------------------------------------------------------------ +/** End a read multiple blocks sequence. + * +* \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + */ +bool Sd2Card::readStop() { + chipSelectLow(); + if (cardCommand(CMD12, 0)) { + error(SD_CARD_ERROR_CMD12); + goto fail; + } + chipSelectHigh(); + return true; + + fail: + chipSelectHigh(); + return false; +} +//------------------------------------------------------------------------------ +/** + * Set the SPI clock rate. + * + * \param[in] sckRateID A value in the range [0, 6]. + * + * The SPI clock will be set to F_CPU/pow(2, 1 + sckRateID). The maximum + * SPI rate is F_CPU/2 for \a sckRateID = 0 and the minimum rate is F_CPU/128 + * for \a scsRateID = 6. + * + * \return The value one, true, is returned for success and the value zero, + * false, is returned for an invalid value of \a sckRateID. + */ +bool Sd2Card::setSckRate(uint8_t sckRateID) { + if (sckRateID > 6) { + error(SD_CARD_ERROR_SCK_RATE); + return false; + } + spiRate_ = sckRateID; + return true; +} +//------------------------------------------------------------------------------ +// wait for card to go not busy +bool Sd2Card::waitNotBusy(uint16_t timeoutMillis) { + uint16_t t0 = millis(); + while (spiRec() != 0XFF) { + if (((uint16_t)millis() - t0) >= timeoutMillis) goto fail; + } + return true; + + fail: + return false; +} +//------------------------------------------------------------------------------ +/** + * Writes a 512 byte block to an SD card. + * + * \param[in] blockNumber Logical block to be written. + * \param[in] src Pointer to the location of the data to be written. + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + */ +bool Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) { + // use address if not SDHC card + if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; + if (cardCommand(CMD24, blockNumber)) { + error(SD_CARD_ERROR_CMD24); + goto fail; + } + if (!writeData(DATA_START_BLOCK, src)) goto fail; + + // wait for flash programming to complete + if (!waitNotBusy(SD_WRITE_TIMEOUT)) { + error(SD_CARD_ERROR_WRITE_TIMEOUT); + goto fail; + } + // response is r2 so get and check two bytes for nonzero + if (cardCommand(CMD13, 0) || spiRec()) { + error(SD_CARD_ERROR_WRITE_PROGRAMMING); + goto fail; + } + chipSelectHigh(); + return true; + + fail: + chipSelectHigh(); + return false; +} +//------------------------------------------------------------------------------ +/** Write one data block in a multiple block write sequence + * \param[in] src Pointer to the location of the data to be written. + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + */ +bool Sd2Card::writeData(const uint8_t* src) { + chipSelectLow(); + // wait for previous write to finish + if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail; + if (!writeData(WRITE_MULTIPLE_TOKEN, src)) goto fail; + chipSelectHigh(); + return true; + + fail: + error(SD_CARD_ERROR_WRITE_MULTIPLE); + chipSelectHigh(); + return false; +} +//------------------------------------------------------------------------------ +// send one block of data for write block or write multiple blocks +bool Sd2Card::writeData(uint8_t token, const uint8_t* src) { + spiSendBlock(token, src); + + spiSend(0xff); // dummy crc + spiSend(0xff); // dummy crc + + status_ = spiRec(); + if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) { + error(SD_CARD_ERROR_WRITE); + goto fail; + } + return true; + + fail: + chipSelectHigh(); + return false; +} +//------------------------------------------------------------------------------ +/** Start a write multiple blocks sequence. + * + * \param[in] blockNumber Address of first block in sequence. + * \param[in] eraseCount The number of blocks to be pre-erased. + * + * \note This function is used with writeData() and writeStop() + * for optimized multiple block writes. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + */ +bool Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) { + // send pre-erase count + if (cardAcmd(ACMD23, eraseCount)) { + error(SD_CARD_ERROR_ACMD23); + goto fail; + } + // use address if not SDHC card + if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; + if (cardCommand(CMD25, blockNumber)) { + error(SD_CARD_ERROR_CMD25); + goto fail; + } + chipSelectHigh(); + return true; + + fail: + chipSelectHigh(); + return false; +} +//------------------------------------------------------------------------------ +/** End a write multiple blocks sequence. + * +* \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + */ +bool Sd2Card::writeStop() { + chipSelectLow(); + if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail; + spiSend(STOP_TRAN_TOKEN); + if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail; + chipSelectHigh(); + return true; + + fail: + error(SD_CARD_ERROR_STOP_TRAN); + chipSelectHigh(); + return false; +} + +//------------------------------------------------------------------------------ +/** Wait for start block token */ +//FIXME Vojtech: Copied from a current version of Sd2Card Arduino code. +// We shall likely upgrade the rest of the Sd2Card. +uint8_t Sd2Card::waitStartBlock(void) { + uint16_t t0 = millis(); + while ((status_ = spiRec()) == 0XFF) { + if (((uint16_t)millis() - t0) > SD_READ_TIMEOUT) { + error(SD_CARD_ERROR_READ_TIMEOUT); + goto fail; + } + } + if (status_ != DATA_START_BLOCK) { + error(SD_CARD_ERROR_READ); + goto fail; + } + return true; + + fail: + chipSelectHigh(); + return false; +} + +// Toshiba FlashAir support, copied from +// https://flashair-developers.com/en/documents/tutorials/arduino/ + +//------------------------------------------------------------------------------ +/** Perform Extention Read. */ +uint8_t Sd2Card::readExt(uint32_t arg, uint8_t* dst, uint16_t count) { + uint16_t i; + + // send command and argument. + if (cardCommand(CMD48, arg)) { + error(SD_CARD_ERROR_CMD48); + goto fail; + } + + // wait for start block token. + if (!waitStartBlock()) { + goto fail; + } + + // receive data + for (i = 0; i < count; ++i) { + dst[i] = spiRec(); + } + + // skip dummy bytes and 16-bit crc. + for (; i < 514; ++i) { + spiRec(); + } + + chipSelectHigh(); + spiSend(0xFF); // dummy clock to force FlashAir finish the command. + return true; + + fail: + chipSelectHigh(); + return false; +} + +//------------------------------------------------------------------------------ +/** + * Read an extension register space. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + */ +uint8_t Sd2Card::readExtMemory(uint8_t mio, uint8_t func, + uint32_t addr, uint16_t count, uint8_t* dst) { + uint32_t offset = addr & 0x1FF; + if (offset + count > 512) count = 512 - offset; + + if (count == 0) return true; + + uint32_t arg = + (((uint32_t)mio & 0x1) << 31) | + (mio ? (((uint32_t)func & 0x7) << 28) : (((uint32_t)func & 0xF) << 27)) | + ((addr & 0x1FFFF) << 9) | + ((count - 1) & 0x1FF); + + return readExt(arg, dst, count); +} + +#endif diff --git a/Firmware/Sd2Card.h b/Firmware/Sd2Card.h index f3936f4d0..537d249c9 100644 --- a/Firmware/Sd2Card.h +++ b/Firmware/Sd2Card.h @@ -1,262 +1,262 @@ -/* Arduino Sd2Card Library - * Copyright (C) 2009 by William Greiman - * - * This file is part of the Arduino Sd2Card Library - * - * This Library is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This Library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the Arduino Sd2Card Library. If not, see - * . - */ - -#include "Marlin.h" -#ifdef SDSUPPORT - -#ifndef Sd2Card_h -#define Sd2Card_h -/** - * \file - * \brief Sd2Card class for V2 SD/SDHC cards - */ -#include "SdFatConfig.h" -#include "Sd2PinMap.h" -#include "SdInfo.h" -//------------------------------------------------------------------------------ -// SPI speed is F_CPU/2^(1 + index), 0 <= index <= 6 -/** Set SCK to max rate of F_CPU/2. See Sd2Card::setSckRate(). */ -uint8_t const SPI_FULL_SPEED = 0; -/** Set SCK rate to F_CPU/4. See Sd2Card::setSckRate(). */ -uint8_t const SPI_HALF_SPEED = 1; -/** Set SCK rate to F_CPU/8. See Sd2Card::setSckRate(). */ -uint8_t const SPI_QUARTER_SPEED = 2; -/** Set SCK rate to F_CPU/16. See Sd2Card::setSckRate(). */ -uint8_t const SPI_EIGHTH_SPEED = 3; -/** Set SCK rate to F_CPU/32. See Sd2Card::setSckRate(). */ -uint8_t const SPI_SIXTEENTH_SPEED = 4; -//------------------------------------------------------------------------------ -/** init timeout ms */ -uint16_t const SD_INIT_TIMEOUT = 2000; -/** erase timeout ms */ -uint16_t const SD_ERASE_TIMEOUT = 10000; -/** read timeout ms */ -uint16_t const SD_READ_TIMEOUT = 300; -/** write time out ms */ -uint16_t const SD_WRITE_TIMEOUT = 600; -//------------------------------------------------------------------------------ -// SD card errors -/** timeout error for command CMD0 (initialize card in SPI mode) */ -uint8_t const SD_CARD_ERROR_CMD0 = 0X1; -/** CMD8 was not accepted - not a valid SD card*/ -uint8_t const SD_CARD_ERROR_CMD8 = 0X2; -/** card returned an error response for CMD12 (write stop) */ -uint8_t const SD_CARD_ERROR_CMD12 = 0X3; -/** card returned an error response for CMD17 (read block) */ -uint8_t const SD_CARD_ERROR_CMD17 = 0X4; -/** card returned an error response for CMD18 (read multiple block) */ -uint8_t const SD_CARD_ERROR_CMD18 = 0X5; -/** card returned an error response for CMD24 (write block) */ -uint8_t const SD_CARD_ERROR_CMD24 = 0X6; -/** WRITE_MULTIPLE_BLOCKS command failed */ -uint8_t const SD_CARD_ERROR_CMD25 = 0X7; -/** card returned an error response for CMD58 (read OCR) */ -uint8_t const SD_CARD_ERROR_CMD58 = 0X8; -/** SET_WR_BLK_ERASE_COUNT failed */ -uint8_t const SD_CARD_ERROR_ACMD23 = 0X9; -/** ACMD41 initialization process timeout */ -uint8_t const SD_CARD_ERROR_ACMD41 = 0XA; -/** card returned a bad CSR version field */ -uint8_t const SD_CARD_ERROR_BAD_CSD = 0XB; -/** erase block group command failed */ -uint8_t const SD_CARD_ERROR_ERASE = 0XC; -/** card not capable of single block erase */ -uint8_t const SD_CARD_ERROR_ERASE_SINGLE_BLOCK = 0XD; -/** Erase sequence timed out */ -uint8_t const SD_CARD_ERROR_ERASE_TIMEOUT = 0XE; -/** card returned an error token instead of read data */ -uint8_t const SD_CARD_ERROR_READ = 0XF; -/** read CID or CSD failed */ -uint8_t const SD_CARD_ERROR_READ_REG = 0X10; -/** timeout while waiting for start of read data */ -uint8_t const SD_CARD_ERROR_READ_TIMEOUT = 0X11; -/** card did not accept STOP_TRAN_TOKEN */ -uint8_t const SD_CARD_ERROR_STOP_TRAN = 0X12; -/** card returned an error token as a response to a write operation */ -uint8_t const SD_CARD_ERROR_WRITE = 0X13; -/** attempt to write protected block zero */ -uint8_t const SD_CARD_ERROR_WRITE_BLOCK_ZERO = 0X14; // REMOVE - not used -/** card did not go ready for a multiple block write */ -uint8_t const SD_CARD_ERROR_WRITE_MULTIPLE = 0X15; -/** card returned an error to a CMD13 status check after a write */ -uint8_t const SD_CARD_ERROR_WRITE_PROGRAMMING = 0X16; -/** timeout occurred during write programming */ -uint8_t const SD_CARD_ERROR_WRITE_TIMEOUT = 0X17; -/** incorrect rate selected */ -uint8_t const SD_CARD_ERROR_SCK_RATE = 0X18; -/** init() not called */ -uint8_t const SD_CARD_ERROR_INIT_NOT_CALLED = 0X19; -/** crc check error */ -uint8_t const SD_CARD_ERROR_CRC = 0X20; - -/** Toshiba FlashAir: iSDIO */ -uint8_t const SD_CARD_ERROR_CMD48 = 0x80; -/** Toshiba FlashAir: iSDIO */ -uint8_t const SD_CARD_ERROR_CMD49 = 0x81; - -//------------------------------------------------------------------------------ -// card types -/** Standard capacity V1 SD card */ -uint8_t const SD_CARD_TYPE_SD1 = 1; -/** Standard capacity V2 SD card */ -uint8_t const SD_CARD_TYPE_SD2 = 2; -/** High Capacity SD card */ -uint8_t const SD_CARD_TYPE_SDHC = 3; -/** - * define SOFTWARE_SPI to use bit-bang SPI - */ -//------------------------------------------------------------------------------ -#if MEGA_SOFT_SPI && (defined(__AVR_ATmega1280__)||defined(__AVR_ATmega2560__)) -#define SOFTWARE_SPI -#elif USE_SOFTWARE_SPI -#define SOFTWARE_SPI -#endif // MEGA_SOFT_SPI -//------------------------------------------------------------------------------ -// SPI pin definitions - do not edit here - change in SdFatConfig.h -// -#ifndef SOFTWARE_SPI -// hardware pin defs -/** The default chip select pin for the SD card is SS. */ -uint8_t const SD_CHIP_SELECT_PIN = SS_PIN; -// The following three pins must not be redefined for hardware SPI. -/** SPI Master Out Slave In pin */ -uint8_t const SPI_MOSI_PIN = MOSI_PIN; -/** SPI Master In Slave Out pin */ -uint8_t const SPI_MISO_PIN = MISO_PIN; -/** SPI Clock pin */ -uint8_t const SPI_SCK_PIN = SCK_PIN; - -#else // SOFTWARE_SPI - -/** SPI chip select pin */ -uint8_t const SD_CHIP_SELECT_PIN = SOFT_SPI_CS_PIN; -/** SPI Master Out Slave In pin */ -uint8_t const SPI_MOSI_PIN = SOFT_SPI_MOSI_PIN; -/** SPI Master In Slave Out pin */ -uint8_t const SPI_MISO_PIN = SOFT_SPI_MISO_PIN; -/** SPI Clock pin */ -uint8_t const SPI_SCK_PIN = SOFT_SPI_SCK_PIN; -#endif // SOFTWARE_SPI -//------------------------------------------------------------------------------ -/** - * \class Sd2Card - * \brief Raw access to SD and SDHC flash memory cards. - */ -class Sd2Card { - public: - /** Construct an instance of Sd2Card. */ - Sd2Card() : errorCode_(SD_CARD_ERROR_INIT_NOT_CALLED), type_(0), flash_air_compatible_(false) {} - uint32_t cardSize(); - bool erase(uint32_t firstBlock, uint32_t lastBlock); - bool eraseSingleBlockEnable(); - /** - * Set SD error code. - * \param[in] code value for error code. - */ - void error(uint8_t code) {errorCode_ = code;} - /** - * \return error code for last error. See Sd2Card.h for a list of error codes. - */ - int errorCode() const {return errorCode_;} - /** \return error data for last error. */ - int errorData() const {return status_;} - /** - * Initialize an SD flash memory card with default clock rate and chip - * select pin. See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin). - * - * \return true for success or false for failure. - */ - bool init(uint8_t sckRateID = SPI_FULL_SPEED, - uint8_t chipSelectPin = SD_CHIP_SELECT_PIN); - bool readBlock(uint32_t block, uint8_t* dst); - /** - * Read a card's CID register. The CID contains card identification - * information such as Manufacturer ID, Product name, Product serial - * number and Manufacturing date. - * - * \param[out] cid pointer to area for returned data. - * - * \return true for success or false for failure. - */ - bool readCID(cid_t* cid) { - return readRegister(CMD10, cid); - } - /** - * Read a card's CSD register. The CSD contains Card-Specific Data that - * provides information regarding access to the card's contents. - * - * \param[out] csd pointer to area for returned data. - * - * \return true for success or false for failure. - */ - bool readCSD(csd_t* csd) { - return readRegister(CMD9, csd); - } - bool readData(uint8_t *dst); - bool readStart(uint32_t blockNumber); - bool readStop(); - bool setSckRate(uint8_t sckRateID); - /** Return the card type: SD V1, SD V2 or SDHC - * \return 0 - SD V1, 1 - SD V2, or 3 - SDHC. - */ - int type() const {return type_;} - bool writeBlock(uint32_t blockNumber, const uint8_t* src); - bool writeData(const uint8_t* src); - bool writeStart(uint32_t blockNumber, uint32_t eraseCount); - bool writeStop(); - - // Toshiba FlashAir support - uint8_t readExtMemory(uint8_t mio, uint8_t func, uint32_t addr, uint16_t count, uint8_t* dst); - - void setFlashAirCompatible(bool flashAirCompatible) { flash_air_compatible_ = flashAirCompatible; } - bool getFlashAirCompatible() const { return flash_air_compatible_; } - - private: - //---------------------------------------------------------------------------- - uint8_t chipSelectPin_; - uint8_t errorCode_; - uint8_t spiRate_; - uint8_t status_; - uint8_t type_; - bool flash_air_compatible_; - // private functions - uint8_t cardAcmd(uint8_t cmd, uint32_t arg) { - cardCommand(CMD55, 0); - return cardCommand(cmd, arg); - } - uint8_t cardCommand(uint8_t cmd, uint32_t arg); - - bool readData(uint8_t* dst, uint16_t count); - bool readRegister(uint8_t cmd, void* buf); - void chipSelectHigh(); - void chipSelectLow(); - void type(uint8_t value) {type_ = value;} - bool waitNotBusy(uint16_t timeoutMillis); - bool writeData(uint8_t token, const uint8_t* src); - - - // Toshiba FlashAir support - uint8_t waitStartBlock(void); - uint8_t readExt(uint32_t arg, uint8_t* dst, uint16_t count); -}; -#endif // Sd2Card_h - - +/* Arduino Sd2Card Library + * Copyright (C) 2009 by William Greiman + * + * This file is part of the Arduino Sd2Card Library + * + * This Library is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This Library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Arduino Sd2Card Library. If not, see + * . + */ + +#include "Marlin.h" +#ifdef SDSUPPORT + +#ifndef Sd2Card_h +#define Sd2Card_h +/** + * \file + * \brief Sd2Card class for V2 SD/SDHC cards + */ +#include "SdFatConfig.h" +#include "Sd2PinMap.h" +#include "SdInfo.h" +//------------------------------------------------------------------------------ +// SPI speed is F_CPU/2^(1 + index), 0 <= index <= 6 +/** Set SCK to max rate of F_CPU/2. See Sd2Card::setSckRate(). */ +uint8_t const SPI_FULL_SPEED = 0; +/** Set SCK rate to F_CPU/4. See Sd2Card::setSckRate(). */ +uint8_t const SPI_HALF_SPEED = 1; +/** Set SCK rate to F_CPU/8. See Sd2Card::setSckRate(). */ +uint8_t const SPI_QUARTER_SPEED = 2; +/** Set SCK rate to F_CPU/16. See Sd2Card::setSckRate(). */ +uint8_t const SPI_EIGHTH_SPEED = 3; +/** Set SCK rate to F_CPU/32. See Sd2Card::setSckRate(). */ +uint8_t const SPI_SIXTEENTH_SPEED = 4; +//------------------------------------------------------------------------------ +/** init timeout ms */ +uint16_t const SD_INIT_TIMEOUT = 2000; +/** erase timeout ms */ +uint16_t const SD_ERASE_TIMEOUT = 10000; +/** read timeout ms */ +uint16_t const SD_READ_TIMEOUT = 300; +/** write time out ms */ +uint16_t const SD_WRITE_TIMEOUT = 600; +//------------------------------------------------------------------------------ +// SD card errors +/** timeout error for command CMD0 (initialize card in SPI mode) */ +uint8_t const SD_CARD_ERROR_CMD0 = 0X1; +/** CMD8 was not accepted - not a valid SD card*/ +uint8_t const SD_CARD_ERROR_CMD8 = 0X2; +/** card returned an error response for CMD12 (write stop) */ +uint8_t const SD_CARD_ERROR_CMD12 = 0X3; +/** card returned an error response for CMD17 (read block) */ +uint8_t const SD_CARD_ERROR_CMD17 = 0X4; +/** card returned an error response for CMD18 (read multiple block) */ +uint8_t const SD_CARD_ERROR_CMD18 = 0X5; +/** card returned an error response for CMD24 (write block) */ +uint8_t const SD_CARD_ERROR_CMD24 = 0X6; +/** WRITE_MULTIPLE_BLOCKS command failed */ +uint8_t const SD_CARD_ERROR_CMD25 = 0X7; +/** card returned an error response for CMD58 (read OCR) */ +uint8_t const SD_CARD_ERROR_CMD58 = 0X8; +/** SET_WR_BLK_ERASE_COUNT failed */ +uint8_t const SD_CARD_ERROR_ACMD23 = 0X9; +/** ACMD41 initialization process timeout */ +uint8_t const SD_CARD_ERROR_ACMD41 = 0XA; +/** card returned a bad CSR version field */ +uint8_t const SD_CARD_ERROR_BAD_CSD = 0XB; +/** erase block group command failed */ +uint8_t const SD_CARD_ERROR_ERASE = 0XC; +/** card not capable of single block erase */ +uint8_t const SD_CARD_ERROR_ERASE_SINGLE_BLOCK = 0XD; +/** Erase sequence timed out */ +uint8_t const SD_CARD_ERROR_ERASE_TIMEOUT = 0XE; +/** card returned an error token instead of read data */ +uint8_t const SD_CARD_ERROR_READ = 0XF; +/** read CID or CSD failed */ +uint8_t const SD_CARD_ERROR_READ_REG = 0X10; +/** timeout while waiting for start of read data */ +uint8_t const SD_CARD_ERROR_READ_TIMEOUT = 0X11; +/** card did not accept STOP_TRAN_TOKEN */ +uint8_t const SD_CARD_ERROR_STOP_TRAN = 0X12; +/** card returned an error token as a response to a write operation */ +uint8_t const SD_CARD_ERROR_WRITE = 0X13; +/** attempt to write protected block zero */ +uint8_t const SD_CARD_ERROR_WRITE_BLOCK_ZERO = 0X14; // REMOVE - not used +/** card did not go ready for a multiple block write */ +uint8_t const SD_CARD_ERROR_WRITE_MULTIPLE = 0X15; +/** card returned an error to a CMD13 status check after a write */ +uint8_t const SD_CARD_ERROR_WRITE_PROGRAMMING = 0X16; +/** timeout occurred during write programming */ +uint8_t const SD_CARD_ERROR_WRITE_TIMEOUT = 0X17; +/** incorrect rate selected */ +uint8_t const SD_CARD_ERROR_SCK_RATE = 0X18; +/** init() not called */ +uint8_t const SD_CARD_ERROR_INIT_NOT_CALLED = 0X19; +/** crc check error */ +uint8_t const SD_CARD_ERROR_CRC = 0X20; + +/** Toshiba FlashAir: iSDIO */ +uint8_t const SD_CARD_ERROR_CMD48 = 0x80; +/** Toshiba FlashAir: iSDIO */ +uint8_t const SD_CARD_ERROR_CMD49 = 0x81; + +//------------------------------------------------------------------------------ +// card types +/** Standard capacity V1 SD card */ +uint8_t const SD_CARD_TYPE_SD1 = 1; +/** Standard capacity V2 SD card */ +uint8_t const SD_CARD_TYPE_SD2 = 2; +/** High Capacity SD card */ +uint8_t const SD_CARD_TYPE_SDHC = 3; +/** + * define SOFTWARE_SPI to use bit-bang SPI + */ +//------------------------------------------------------------------------------ +#if MEGA_SOFT_SPI && (defined(__AVR_ATmega1280__)||defined(__AVR_ATmega2560__)) +#define SOFTWARE_SPI +#elif USE_SOFTWARE_SPI +#define SOFTWARE_SPI +#endif // MEGA_SOFT_SPI +//------------------------------------------------------------------------------ +// SPI pin definitions - do not edit here - change in SdFatConfig.h +// +#ifndef SOFTWARE_SPI +// hardware pin defs +/** The default chip select pin for the SD card is SS. */ +uint8_t const SD_CHIP_SELECT_PIN = SS_PIN; +// The following three pins must not be redefined for hardware SPI. +/** SPI Master Out Slave In pin */ +uint8_t const SPI_MOSI_PIN = MOSI_PIN; +/** SPI Master In Slave Out pin */ +uint8_t const SPI_MISO_PIN = MISO_PIN; +/** SPI Clock pin */ +uint8_t const SPI_SCK_PIN = SCK_PIN; + +#else // SOFTWARE_SPI + +/** SPI chip select pin */ +uint8_t const SD_CHIP_SELECT_PIN = SOFT_SPI_CS_PIN; +/** SPI Master Out Slave In pin */ +uint8_t const SPI_MOSI_PIN = SOFT_SPI_MOSI_PIN; +/** SPI Master In Slave Out pin */ +uint8_t const SPI_MISO_PIN = SOFT_SPI_MISO_PIN; +/** SPI Clock pin */ +uint8_t const SPI_SCK_PIN = SOFT_SPI_SCK_PIN; +#endif // SOFTWARE_SPI +//------------------------------------------------------------------------------ +/** + * \class Sd2Card + * \brief Raw access to SD and SDHC flash memory cards. + */ +class Sd2Card { + public: + /** Construct an instance of Sd2Card. */ + Sd2Card() : errorCode_(SD_CARD_ERROR_INIT_NOT_CALLED), type_(0), flash_air_compatible_(false) {} + uint32_t cardSize(); + bool erase(uint32_t firstBlock, uint32_t lastBlock); + bool eraseSingleBlockEnable(); + /** + * Set SD error code. + * \param[in] code value for error code. + */ + void error(uint8_t code) {errorCode_ = code;} + /** + * \return error code for last error. See Sd2Card.h for a list of error codes. + */ + int errorCode() const {return errorCode_;} + /** \return error data for last error. */ + int errorData() const {return status_;} + /** + * Initialize an SD flash memory card with default clock rate and chip + * select pin. See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin). + * + * \return true for success or false for failure. + */ + bool init(uint8_t sckRateID = SPI_FULL_SPEED, + uint8_t chipSelectPin = SD_CHIP_SELECT_PIN); + bool readBlock(uint32_t block, uint8_t* dst); + /** + * Read a card's CID register. The CID contains card identification + * information such as Manufacturer ID, Product name, Product serial + * number and Manufacturing date. + * + * \param[out] cid pointer to area for returned data. + * + * \return true for success or false for failure. + */ + bool readCID(cid_t* cid) { + return readRegister(CMD10, cid); + } + /** + * Read a card's CSD register. The CSD contains Card-Specific Data that + * provides information regarding access to the card's contents. + * + * \param[out] csd pointer to area for returned data. + * + * \return true for success or false for failure. + */ + bool readCSD(csd_t* csd) { + return readRegister(CMD9, csd); + } + bool readData(uint8_t *dst); + bool readStart(uint32_t blockNumber); + bool readStop(); + bool setSckRate(uint8_t sckRateID); + /** Return the card type: SD V1, SD V2 or SDHC + * \return 0 - SD V1, 1 - SD V2, or 3 - SDHC. + */ + int type() const {return type_;} + bool writeBlock(uint32_t blockNumber, const uint8_t* src); + bool writeData(const uint8_t* src); + bool writeStart(uint32_t blockNumber, uint32_t eraseCount); + bool writeStop(); + + // Toshiba FlashAir support + uint8_t readExtMemory(uint8_t mio, uint8_t func, uint32_t addr, uint16_t count, uint8_t* dst); + + void setFlashAirCompatible(bool flashAirCompatible) { flash_air_compatible_ = flashAirCompatible; } + bool getFlashAirCompatible() const { return flash_air_compatible_; } + + private: + //---------------------------------------------------------------------------- + uint8_t chipSelectPin_; + uint8_t errorCode_; + uint8_t spiRate_; + uint8_t status_; + uint8_t type_; + bool flash_air_compatible_; + // private functions + uint8_t cardAcmd(uint8_t cmd, uint32_t arg) { + cardCommand(CMD55, 0); + return cardCommand(cmd, arg); + } + uint8_t cardCommand(uint8_t cmd, uint32_t arg); + + bool readData(uint8_t* dst, uint16_t count); + bool readRegister(uint8_t cmd, void* buf); + void chipSelectHigh(); + void chipSelectLow(); + void type(uint8_t value) {type_ = value;} + bool waitNotBusy(uint16_t timeoutMillis); + bool writeData(uint8_t token, const uint8_t* src); + + + // Toshiba FlashAir support + uint8_t waitStartBlock(void); + uint8_t readExt(uint32_t arg, uint8_t* dst, uint16_t count); +}; +#endif // Sd2Card_h + + #endif \ No newline at end of file diff --git a/Firmware/Sd2PinMap.h b/Firmware/Sd2PinMap.h index 93ab943ce..8a608731e 100644 --- a/Firmware/Sd2PinMap.h +++ b/Firmware/Sd2PinMap.h @@ -1,368 +1,368 @@ -/* Arduino SdFat Library - * Copyright (C) 2010 by William Greiman - * - * This file is part of the Arduino SdFat Library - * - * This Library is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This Library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the Arduino SdFat Library. If not, see - * . - */ -// Warning this file was generated by a program. -#include "Marlin.h" -#ifdef SDSUPPORT - -#ifndef Sd2PinMap_h -#define Sd2PinMap_h -#include -//------------------------------------------------------------------------------ -/** struct for mapping digital pins */ -struct pin_map_t { - volatile uint8_t* ddr; - volatile uint8_t* pin; - volatile uint8_t* port; - uint8_t bit; -}; -//------------------------------------------------------------------------------ -#if defined(__AVR_ATmega1280__)\ -|| defined(__AVR_ATmega2560__) -// Mega - -// Two Wire (aka I2C) ports -uint8_t const SDA_PIN = 20; // D1 -uint8_t const SCL_PIN = 21; // D0 - -#undef MOSI_PIN -#undef MISO_PIN -// SPI port -uint8_t const SS_PIN = 53; // B0 -uint8_t const MOSI_PIN = 51; // B2 -uint8_t const MISO_PIN = 50; // B3 -uint8_t const SCK_PIN = 52; // B1 - -static const pin_map_t digitalPinMap[] = { - {&DDRE, &PINE, &PORTE, 0}, // E0 0 - {&DDRE, &PINE, &PORTE, 1}, // E1 1 - {&DDRE, &PINE, &PORTE, 4}, // E4 2 - {&DDRE, &PINE, &PORTE, 5}, // E5 3 - {&DDRG, &PING, &PORTG, 5}, // G5 4 - {&DDRE, &PINE, &PORTE, 3}, // E3 5 - {&DDRH, &PINH, &PORTH, 3}, // H3 6 - {&DDRH, &PINH, &PORTH, 4}, // H4 7 - {&DDRH, &PINH, &PORTH, 5}, // H5 8 - {&DDRH, &PINH, &PORTH, 6}, // H6 9 - {&DDRB, &PINB, &PORTB, 4}, // B4 10 - {&DDRB, &PINB, &PORTB, 5}, // B5 11 - {&DDRB, &PINB, &PORTB, 6}, // B6 12 - {&DDRB, &PINB, &PORTB, 7}, // B7 13 - {&DDRJ, &PINJ, &PORTJ, 1}, // J1 14 - {&DDRJ, &PINJ, &PORTJ, 0}, // J0 15 - {&DDRH, &PINH, &PORTH, 1}, // H1 16 - {&DDRH, &PINH, &PORTH, 0}, // H0 17 - {&DDRD, &PIND, &PORTD, 3}, // D3 18 - {&DDRD, &PIND, &PORTD, 2}, // D2 19 - {&DDRD, &PIND, &PORTD, 1}, // D1 20 - {&DDRD, &PIND, &PORTD, 0}, // D0 21 - {&DDRA, &PINA, &PORTA, 0}, // A0 22 - {&DDRA, &PINA, &PORTA, 1}, // A1 23 - {&DDRA, &PINA, &PORTA, 2}, // A2 24 - {&DDRA, &PINA, &PORTA, 3}, // A3 25 - {&DDRA, &PINA, &PORTA, 4}, // A4 26 - {&DDRA, &PINA, &PORTA, 5}, // A5 27 - {&DDRA, &PINA, &PORTA, 6}, // A6 28 - {&DDRA, &PINA, &PORTA, 7}, // A7 29 - {&DDRC, &PINC, &PORTC, 7}, // C7 30 - {&DDRC, &PINC, &PORTC, 6}, // C6 31 - {&DDRC, &PINC, &PORTC, 5}, // C5 32 - {&DDRC, &PINC, &PORTC, 4}, // C4 33 - {&DDRC, &PINC, &PORTC, 3}, // C3 34 - {&DDRC, &PINC, &PORTC, 2}, // C2 35 - {&DDRC, &PINC, &PORTC, 1}, // C1 36 - {&DDRC, &PINC, &PORTC, 0}, // C0 37 - {&DDRD, &PIND, &PORTD, 7}, // D7 38 - {&DDRG, &PING, &PORTG, 2}, // G2 39 - {&DDRG, &PING, &PORTG, 1}, // G1 40 - {&DDRG, &PING, &PORTG, 0}, // G0 41 - {&DDRL, &PINL, &PORTL, 7}, // L7 42 - {&DDRL, &PINL, &PORTL, 6}, // L6 43 - {&DDRL, &PINL, &PORTL, 5}, // L5 44 - {&DDRL, &PINL, &PORTL, 4}, // L4 45 - {&DDRL, &PINL, &PORTL, 3}, // L3 46 - {&DDRL, &PINL, &PORTL, 2}, // L2 47 - {&DDRL, &PINL, &PORTL, 1}, // L1 48 - {&DDRL, &PINL, &PORTL, 0}, // L0 49 - {&DDRB, &PINB, &PORTB, 3}, // B3 50 - {&DDRB, &PINB, &PORTB, 2}, // B2 51 - {&DDRB, &PINB, &PORTB, 1}, // B1 52 - {&DDRB, &PINB, &PORTB, 0}, // B0 53 - {&DDRF, &PINF, &PORTF, 0}, // F0 54 - {&DDRF, &PINF, &PORTF, 1}, // F1 55 - {&DDRF, &PINF, &PORTF, 2}, // F2 56 - {&DDRF, &PINF, &PORTF, 3}, // F3 57 - {&DDRF, &PINF, &PORTF, 4}, // F4 58 - {&DDRF, &PINF, &PORTF, 5}, // F5 59 - {&DDRF, &PINF, &PORTF, 6}, // F6 60 - {&DDRF, &PINF, &PORTF, 7}, // F7 61 - {&DDRK, &PINK, &PORTK, 0}, // K0 62 - {&DDRK, &PINK, &PORTK, 1}, // K1 63 - {&DDRK, &PINK, &PORTK, 2}, // K2 64 - {&DDRK, &PINK, &PORTK, 3}, // K3 65 - {&DDRK, &PINK, &PORTK, 4}, // K4 66 - {&DDRK, &PINK, &PORTK, 5}, // K5 67 - {&DDRK, &PINK, &PORTK, 6}, // K6 68 - {&DDRK, &PINK, &PORTK, 7} // K7 69 -}; -//------------------------------------------------------------------------------ -#elif defined(__AVR_ATmega644P__)\ -|| defined(__AVR_ATmega644__)\ -|| defined(__AVR_ATmega1284P__) -// Sanguino - -// Two Wire (aka I2C) ports -uint8_t const SDA_PIN = 17; // C1 -uint8_t const SCL_PIN = 18; // C2 - -// SPI port -uint8_t const SS_PIN = 4; // B4 -uint8_t const MOSI_PIN = 5; // B5 -uint8_t const MISO_PIN = 6; // B6 -uint8_t const SCK_PIN = 7; // B7 - -static const pin_map_t digitalPinMap[] = { - {&DDRB, &PINB, &PORTB, 0}, // B0 0 - {&DDRB, &PINB, &PORTB, 1}, // B1 1 - {&DDRB, &PINB, &PORTB, 2}, // B2 2 - {&DDRB, &PINB, &PORTB, 3}, // B3 3 - {&DDRB, &PINB, &PORTB, 4}, // B4 4 - {&DDRB, &PINB, &PORTB, 5}, // B5 5 - {&DDRB, &PINB, &PORTB, 6}, // B6 6 - {&DDRB, &PINB, &PORTB, 7}, // B7 7 - {&DDRD, &PIND, &PORTD, 0}, // D0 8 - {&DDRD, &PIND, &PORTD, 1}, // D1 9 - {&DDRD, &PIND, &PORTD, 2}, // D2 10 - {&DDRD, &PIND, &PORTD, 3}, // D3 11 - {&DDRD, &PIND, &PORTD, 4}, // D4 12 - {&DDRD, &PIND, &PORTD, 5}, // D5 13 - {&DDRD, &PIND, &PORTD, 6}, // D6 14 - {&DDRD, &PIND, &PORTD, 7}, // D7 15 - {&DDRC, &PINC, &PORTC, 0}, // C0 16 - {&DDRC, &PINC, &PORTC, 1}, // C1 17 - {&DDRC, &PINC, &PORTC, 2}, // C2 18 - {&DDRC, &PINC, &PORTC, 3}, // C3 19 - {&DDRC, &PINC, &PORTC, 4}, // C4 20 - {&DDRC, &PINC, &PORTC, 5}, // C5 21 - {&DDRC, &PINC, &PORTC, 6}, // C6 22 - {&DDRC, &PINC, &PORTC, 7}, // C7 23 - {&DDRA, &PINA, &PORTA, 7}, // A7 24 - {&DDRA, &PINA, &PORTA, 6}, // A6 25 - {&DDRA, &PINA, &PORTA, 5}, // A5 26 - {&DDRA, &PINA, &PORTA, 4}, // A4 27 - {&DDRA, &PINA, &PORTA, 3}, // A3 28 - {&DDRA, &PINA, &PORTA, 2}, // A2 29 - {&DDRA, &PINA, &PORTA, 1}, // A1 30 - {&DDRA, &PINA, &PORTA, 0} // A0 31 -}; -//------------------------------------------------------------------------------ -#elif defined(__AVR_ATmega32U4__) -// Teensy 2.0 - -// Two Wire (aka I2C) ports -uint8_t const SDA_PIN = 6; // D1 -uint8_t const SCL_PIN = 5; // D0 - -// SPI port -uint8_t const SS_PIN = 0; // B0 -uint8_t const MOSI_PIN = 2; // B2 -uint8_t const MISO_PIN = 3; // B3 -uint8_t const SCK_PIN = 1; // B1 - -static const pin_map_t digitalPinMap[] = { - {&DDRB, &PINB, &PORTB, 0}, // B0 0 - {&DDRB, &PINB, &PORTB, 1}, // B1 1 - {&DDRB, &PINB, &PORTB, 2}, // B2 2 - {&DDRB, &PINB, &PORTB, 3}, // B3 3 - {&DDRB, &PINB, &PORTB, 7}, // B7 4 - {&DDRD, &PIND, &PORTD, 0}, // D0 5 - {&DDRD, &PIND, &PORTD, 1}, // D1 6 - {&DDRD, &PIND, &PORTD, 2}, // D2 7 - {&DDRD, &PIND, &PORTD, 3}, // D3 8 - {&DDRC, &PINC, &PORTC, 6}, // C6 9 - {&DDRC, &PINC, &PORTC, 7}, // C7 10 - {&DDRD, &PIND, &PORTD, 6}, // D6 11 - {&DDRD, &PIND, &PORTD, 7}, // D7 12 - {&DDRB, &PINB, &PORTB, 4}, // B4 13 - {&DDRB, &PINB, &PORTB, 5}, // B5 14 - {&DDRB, &PINB, &PORTB, 6}, // B6 15 - {&DDRF, &PINF, &PORTF, 7}, // F7 16 - {&DDRF, &PINF, &PORTF, 6}, // F6 17 - {&DDRF, &PINF, &PORTF, 5}, // F5 18 - {&DDRF, &PINF, &PORTF, 4}, // F4 19 - {&DDRF, &PINF, &PORTF, 1}, // F1 20 - {&DDRF, &PINF, &PORTF, 0}, // F0 21 - {&DDRD, &PIND, &PORTD, 4}, // D4 22 - {&DDRD, &PIND, &PORTD, 5}, // D5 23 - {&DDRE, &PINE, &PORTE, 6} // E6 24 -}; -//------------------------------------------------------------------------------ -#elif defined(__AVR_AT90USB646__)\ -|| defined(__AVR_AT90USB1286__) -// Teensy++ 1.0 & 2.0 - -// Two Wire (aka I2C) ports -uint8_t const SDA_PIN = 1; // D1 -uint8_t const SCL_PIN = 0; // D0 - -// SPI port -uint8_t const SS_PIN = 20; // B0 -uint8_t const MOSI_PIN = 22; // B2 -uint8_t const MISO_PIN = 23; // B3 -uint8_t const SCK_PIN = 21; // B1 - -static const pin_map_t digitalPinMap[] = { - {&DDRD, &PIND, &PORTD, 0}, // D0 0 - {&DDRD, &PIND, &PORTD, 1}, // D1 1 - {&DDRD, &PIND, &PORTD, 2}, // D2 2 - {&DDRD, &PIND, &PORTD, 3}, // D3 3 - {&DDRD, &PIND, &PORTD, 4}, // D4 4 - {&DDRD, &PIND, &PORTD, 5}, // D5 5 - {&DDRD, &PIND, &PORTD, 6}, // D6 6 - {&DDRD, &PIND, &PORTD, 7}, // D7 7 - {&DDRE, &PINE, &PORTE, 0}, // E0 8 - {&DDRE, &PINE, &PORTE, 1}, // E1 9 - {&DDRC, &PINC, &PORTC, 0}, // C0 10 - {&DDRC, &PINC, &PORTC, 1}, // C1 11 - {&DDRC, &PINC, &PORTC, 2}, // C2 12 - {&DDRC, &PINC, &PORTC, 3}, // C3 13 - {&DDRC, &PINC, &PORTC, 4}, // C4 14 - {&DDRC, &PINC, &PORTC, 5}, // C5 15 - {&DDRC, &PINC, &PORTC, 6}, // C6 16 - {&DDRC, &PINC, &PORTC, 7}, // C7 17 - {&DDRE, &PINE, &PORTE, 6}, // E6 18 - {&DDRE, &PINE, &PORTE, 7}, // E7 19 - {&DDRB, &PINB, &PORTB, 0}, // B0 20 - {&DDRB, &PINB, &PORTB, 1}, // B1 21 - {&DDRB, &PINB, &PORTB, 2}, // B2 22 - {&DDRB, &PINB, &PORTB, 3}, // B3 23 - {&DDRB, &PINB, &PORTB, 4}, // B4 24 - {&DDRB, &PINB, &PORTB, 5}, // B5 25 - {&DDRB, &PINB, &PORTB, 6}, // B6 26 - {&DDRB, &PINB, &PORTB, 7}, // B7 27 - {&DDRA, &PINA, &PORTA, 0}, // A0 28 - {&DDRA, &PINA, &PORTA, 1}, // A1 29 - {&DDRA, &PINA, &PORTA, 2}, // A2 30 - {&DDRA, &PINA, &PORTA, 3}, // A3 31 - {&DDRA, &PINA, &PORTA, 4}, // A4 32 - {&DDRA, &PINA, &PORTA, 5}, // A5 33 - {&DDRA, &PINA, &PORTA, 6}, // A6 34 - {&DDRA, &PINA, &PORTA, 7}, // A7 35 - {&DDRE, &PINE, &PORTE, 4}, // E4 36 - {&DDRE, &PINE, &PORTE, 5}, // E5 37 - {&DDRF, &PINF, &PORTF, 0}, // F0 38 - {&DDRF, &PINF, &PORTF, 1}, // F1 39 - {&DDRF, &PINF, &PORTF, 2}, // F2 40 - {&DDRF, &PINF, &PORTF, 3}, // F3 41 - {&DDRF, &PINF, &PORTF, 4}, // F4 42 - {&DDRF, &PINF, &PORTF, 5}, // F5 43 - {&DDRF, &PINF, &PORTF, 6}, // F6 44 - {&DDRF, &PINF, &PORTF, 7} // F7 45 -}; -//------------------------------------------------------------------------------ -#elif defined(__AVR_ATmega168__)\ -||defined(__AVR_ATmega168P__)\ -||defined(__AVR_ATmega328P__) -// 168 and 328 Arduinos - -// Two Wire (aka I2C) ports -uint8_t const SDA_PIN = 18; // C4 -uint8_t const SCL_PIN = 19; // C5 - -// SPI port -uint8_t const SS_PIN = 10; // B2 -uint8_t const MOSI_PIN = 11; // B3 -uint8_t const MISO_PIN = 12; // B4 -uint8_t const SCK_PIN = 13; // B5 - -static const pin_map_t digitalPinMap[] = { - {&DDRD, &PIND, &PORTD, 0}, // D0 0 - {&DDRD, &PIND, &PORTD, 1}, // D1 1 - {&DDRD, &PIND, &PORTD, 2}, // D2 2 - {&DDRD, &PIND, &PORTD, 3}, // D3 3 - {&DDRD, &PIND, &PORTD, 4}, // D4 4 - {&DDRD, &PIND, &PORTD, 5}, // D5 5 - {&DDRD, &PIND, &PORTD, 6}, // D6 6 - {&DDRD, &PIND, &PORTD, 7}, // D7 7 - {&DDRB, &PINB, &PORTB, 0}, // B0 8 - {&DDRB, &PINB, &PORTB, 1}, // B1 9 - {&DDRB, &PINB, &PORTB, 2}, // B2 10 - {&DDRB, &PINB, &PORTB, 3}, // B3 11 - {&DDRB, &PINB, &PORTB, 4}, // B4 12 - {&DDRB, &PINB, &PORTB, 5}, // B5 13 - {&DDRC, &PINC, &PORTC, 0}, // C0 14 - {&DDRC, &PINC, &PORTC, 1}, // C1 15 - {&DDRC, &PINC, &PORTC, 2}, // C2 16 - {&DDRC, &PINC, &PORTC, 3}, // C3 17 - {&DDRC, &PINC, &PORTC, 4}, // C4 18 - {&DDRC, &PINC, &PORTC, 5} // C5 19 -}; -#else // defined(__AVR_ATmega1280__) -#error unknown chip -#endif // defined(__AVR_ATmega1280__) -//------------------------------------------------------------------------------ -static const uint8_t digitalPinCount = sizeof(digitalPinMap)/sizeof(pin_map_t); - -uint8_t badPinNumber(void) - __attribute__((error("Pin number is too large or not a constant"))); - -static inline __attribute__((always_inline)) - bool getPinMode(uint8_t pin) { - if (__builtin_constant_p(pin) && pin < digitalPinCount) { - return (*digitalPinMap[pin].ddr >> digitalPinMap[pin].bit) & 1; - } else { - return badPinNumber(); - } -} -static inline __attribute__((always_inline)) - void setPinMode(uint8_t pin, uint8_t mode) { - if (__builtin_constant_p(pin) && pin < digitalPinCount) { - if (mode) { - *digitalPinMap[pin].ddr |= 1 << digitalPinMap[pin].bit; - } else { - *digitalPinMap[pin].ddr &= ~(1 << digitalPinMap[pin].bit); - } - } else { - badPinNumber(); - } -} -static inline __attribute__((always_inline)) - bool fastDigitalRead(uint8_t pin) { - if (__builtin_constant_p(pin) && pin < digitalPinCount) { - return (*digitalPinMap[pin].pin >> digitalPinMap[pin].bit) & 1; - } else { - return badPinNumber(); - } -} -static inline __attribute__((always_inline)) - void fastDigitalWrite(uint8_t pin, uint8_t value) { - if (__builtin_constant_p(pin) && pin < digitalPinCount) { - if (value) { - *digitalPinMap[pin].port |= 1 << digitalPinMap[pin].bit; - } else { - *digitalPinMap[pin].port &= ~(1 << digitalPinMap[pin].bit); - } - } else { - badPinNumber(); - } -} -#endif // Sd2PinMap_h - - +/* Arduino SdFat Library + * Copyright (C) 2010 by William Greiman + * + * This file is part of the Arduino SdFat Library + * + * This Library is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This Library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Arduino SdFat Library. If not, see + * . + */ +// Warning this file was generated by a program. +#include "Marlin.h" +#ifdef SDSUPPORT + +#ifndef Sd2PinMap_h +#define Sd2PinMap_h +#include +//------------------------------------------------------------------------------ +/** struct for mapping digital pins */ +struct pin_map_t { + volatile uint8_t* ddr; + volatile uint8_t* pin; + volatile uint8_t* port; + uint8_t bit; +}; +//------------------------------------------------------------------------------ +#if defined(__AVR_ATmega1280__)\ +|| defined(__AVR_ATmega2560__) +// Mega + +// Two Wire (aka I2C) ports +uint8_t const SDA_PIN = 20; // D1 +uint8_t const SCL_PIN = 21; // D0 + +#undef MOSI_PIN +#undef MISO_PIN +// SPI port +uint8_t const SS_PIN = 53; // B0 +uint8_t const MOSI_PIN = 51; // B2 +uint8_t const MISO_PIN = 50; // B3 +uint8_t const SCK_PIN = 52; // B1 + +static const pin_map_t digitalPinMap[] = { + {&DDRE, &PINE, &PORTE, 0}, // E0 0 + {&DDRE, &PINE, &PORTE, 1}, // E1 1 + {&DDRE, &PINE, &PORTE, 4}, // E4 2 + {&DDRE, &PINE, &PORTE, 5}, // E5 3 + {&DDRG, &PING, &PORTG, 5}, // G5 4 + {&DDRE, &PINE, &PORTE, 3}, // E3 5 + {&DDRH, &PINH, &PORTH, 3}, // H3 6 + {&DDRH, &PINH, &PORTH, 4}, // H4 7 + {&DDRH, &PINH, &PORTH, 5}, // H5 8 + {&DDRH, &PINH, &PORTH, 6}, // H6 9 + {&DDRB, &PINB, &PORTB, 4}, // B4 10 + {&DDRB, &PINB, &PORTB, 5}, // B5 11 + {&DDRB, &PINB, &PORTB, 6}, // B6 12 + {&DDRB, &PINB, &PORTB, 7}, // B7 13 + {&DDRJ, &PINJ, &PORTJ, 1}, // J1 14 + {&DDRJ, &PINJ, &PORTJ, 0}, // J0 15 + {&DDRH, &PINH, &PORTH, 1}, // H1 16 + {&DDRH, &PINH, &PORTH, 0}, // H0 17 + {&DDRD, &PIND, &PORTD, 3}, // D3 18 + {&DDRD, &PIND, &PORTD, 2}, // D2 19 + {&DDRD, &PIND, &PORTD, 1}, // D1 20 + {&DDRD, &PIND, &PORTD, 0}, // D0 21 + {&DDRA, &PINA, &PORTA, 0}, // A0 22 + {&DDRA, &PINA, &PORTA, 1}, // A1 23 + {&DDRA, &PINA, &PORTA, 2}, // A2 24 + {&DDRA, &PINA, &PORTA, 3}, // A3 25 + {&DDRA, &PINA, &PORTA, 4}, // A4 26 + {&DDRA, &PINA, &PORTA, 5}, // A5 27 + {&DDRA, &PINA, &PORTA, 6}, // A6 28 + {&DDRA, &PINA, &PORTA, 7}, // A7 29 + {&DDRC, &PINC, &PORTC, 7}, // C7 30 + {&DDRC, &PINC, &PORTC, 6}, // C6 31 + {&DDRC, &PINC, &PORTC, 5}, // C5 32 + {&DDRC, &PINC, &PORTC, 4}, // C4 33 + {&DDRC, &PINC, &PORTC, 3}, // C3 34 + {&DDRC, &PINC, &PORTC, 2}, // C2 35 + {&DDRC, &PINC, &PORTC, 1}, // C1 36 + {&DDRC, &PINC, &PORTC, 0}, // C0 37 + {&DDRD, &PIND, &PORTD, 7}, // D7 38 + {&DDRG, &PING, &PORTG, 2}, // G2 39 + {&DDRG, &PING, &PORTG, 1}, // G1 40 + {&DDRG, &PING, &PORTG, 0}, // G0 41 + {&DDRL, &PINL, &PORTL, 7}, // L7 42 + {&DDRL, &PINL, &PORTL, 6}, // L6 43 + {&DDRL, &PINL, &PORTL, 5}, // L5 44 + {&DDRL, &PINL, &PORTL, 4}, // L4 45 + {&DDRL, &PINL, &PORTL, 3}, // L3 46 + {&DDRL, &PINL, &PORTL, 2}, // L2 47 + {&DDRL, &PINL, &PORTL, 1}, // L1 48 + {&DDRL, &PINL, &PORTL, 0}, // L0 49 + {&DDRB, &PINB, &PORTB, 3}, // B3 50 + {&DDRB, &PINB, &PORTB, 2}, // B2 51 + {&DDRB, &PINB, &PORTB, 1}, // B1 52 + {&DDRB, &PINB, &PORTB, 0}, // B0 53 + {&DDRF, &PINF, &PORTF, 0}, // F0 54 + {&DDRF, &PINF, &PORTF, 1}, // F1 55 + {&DDRF, &PINF, &PORTF, 2}, // F2 56 + {&DDRF, &PINF, &PORTF, 3}, // F3 57 + {&DDRF, &PINF, &PORTF, 4}, // F4 58 + {&DDRF, &PINF, &PORTF, 5}, // F5 59 + {&DDRF, &PINF, &PORTF, 6}, // F6 60 + {&DDRF, &PINF, &PORTF, 7}, // F7 61 + {&DDRK, &PINK, &PORTK, 0}, // K0 62 + {&DDRK, &PINK, &PORTK, 1}, // K1 63 + {&DDRK, &PINK, &PORTK, 2}, // K2 64 + {&DDRK, &PINK, &PORTK, 3}, // K3 65 + {&DDRK, &PINK, &PORTK, 4}, // K4 66 + {&DDRK, &PINK, &PORTK, 5}, // K5 67 + {&DDRK, &PINK, &PORTK, 6}, // K6 68 + {&DDRK, &PINK, &PORTK, 7} // K7 69 +}; +//------------------------------------------------------------------------------ +#elif defined(__AVR_ATmega644P__)\ +|| defined(__AVR_ATmega644__)\ +|| defined(__AVR_ATmega1284P__) +// Sanguino + +// Two Wire (aka I2C) ports +uint8_t const SDA_PIN = 17; // C1 +uint8_t const SCL_PIN = 18; // C2 + +// SPI port +uint8_t const SS_PIN = 4; // B4 +uint8_t const MOSI_PIN = 5; // B5 +uint8_t const MISO_PIN = 6; // B6 +uint8_t const SCK_PIN = 7; // B7 + +static const pin_map_t digitalPinMap[] = { + {&DDRB, &PINB, &PORTB, 0}, // B0 0 + {&DDRB, &PINB, &PORTB, 1}, // B1 1 + {&DDRB, &PINB, &PORTB, 2}, // B2 2 + {&DDRB, &PINB, &PORTB, 3}, // B3 3 + {&DDRB, &PINB, &PORTB, 4}, // B4 4 + {&DDRB, &PINB, &PORTB, 5}, // B5 5 + {&DDRB, &PINB, &PORTB, 6}, // B6 6 + {&DDRB, &PINB, &PORTB, 7}, // B7 7 + {&DDRD, &PIND, &PORTD, 0}, // D0 8 + {&DDRD, &PIND, &PORTD, 1}, // D1 9 + {&DDRD, &PIND, &PORTD, 2}, // D2 10 + {&DDRD, &PIND, &PORTD, 3}, // D3 11 + {&DDRD, &PIND, &PORTD, 4}, // D4 12 + {&DDRD, &PIND, &PORTD, 5}, // D5 13 + {&DDRD, &PIND, &PORTD, 6}, // D6 14 + {&DDRD, &PIND, &PORTD, 7}, // D7 15 + {&DDRC, &PINC, &PORTC, 0}, // C0 16 + {&DDRC, &PINC, &PORTC, 1}, // C1 17 + {&DDRC, &PINC, &PORTC, 2}, // C2 18 + {&DDRC, &PINC, &PORTC, 3}, // C3 19 + {&DDRC, &PINC, &PORTC, 4}, // C4 20 + {&DDRC, &PINC, &PORTC, 5}, // C5 21 + {&DDRC, &PINC, &PORTC, 6}, // C6 22 + {&DDRC, &PINC, &PORTC, 7}, // C7 23 + {&DDRA, &PINA, &PORTA, 7}, // A7 24 + {&DDRA, &PINA, &PORTA, 6}, // A6 25 + {&DDRA, &PINA, &PORTA, 5}, // A5 26 + {&DDRA, &PINA, &PORTA, 4}, // A4 27 + {&DDRA, &PINA, &PORTA, 3}, // A3 28 + {&DDRA, &PINA, &PORTA, 2}, // A2 29 + {&DDRA, &PINA, &PORTA, 1}, // A1 30 + {&DDRA, &PINA, &PORTA, 0} // A0 31 +}; +//------------------------------------------------------------------------------ +#elif defined(__AVR_ATmega32U4__) +// Teensy 2.0 + +// Two Wire (aka I2C) ports +uint8_t const SDA_PIN = 6; // D1 +uint8_t const SCL_PIN = 5; // D0 + +// SPI port +uint8_t const SS_PIN = 0; // B0 +uint8_t const MOSI_PIN = 2; // B2 +uint8_t const MISO_PIN = 3; // B3 +uint8_t const SCK_PIN = 1; // B1 + +static const pin_map_t digitalPinMap[] = { + {&DDRB, &PINB, &PORTB, 0}, // B0 0 + {&DDRB, &PINB, &PORTB, 1}, // B1 1 + {&DDRB, &PINB, &PORTB, 2}, // B2 2 + {&DDRB, &PINB, &PORTB, 3}, // B3 3 + {&DDRB, &PINB, &PORTB, 7}, // B7 4 + {&DDRD, &PIND, &PORTD, 0}, // D0 5 + {&DDRD, &PIND, &PORTD, 1}, // D1 6 + {&DDRD, &PIND, &PORTD, 2}, // D2 7 + {&DDRD, &PIND, &PORTD, 3}, // D3 8 + {&DDRC, &PINC, &PORTC, 6}, // C6 9 + {&DDRC, &PINC, &PORTC, 7}, // C7 10 + {&DDRD, &PIND, &PORTD, 6}, // D6 11 + {&DDRD, &PIND, &PORTD, 7}, // D7 12 + {&DDRB, &PINB, &PORTB, 4}, // B4 13 + {&DDRB, &PINB, &PORTB, 5}, // B5 14 + {&DDRB, &PINB, &PORTB, 6}, // B6 15 + {&DDRF, &PINF, &PORTF, 7}, // F7 16 + {&DDRF, &PINF, &PORTF, 6}, // F6 17 + {&DDRF, &PINF, &PORTF, 5}, // F5 18 + {&DDRF, &PINF, &PORTF, 4}, // F4 19 + {&DDRF, &PINF, &PORTF, 1}, // F1 20 + {&DDRF, &PINF, &PORTF, 0}, // F0 21 + {&DDRD, &PIND, &PORTD, 4}, // D4 22 + {&DDRD, &PIND, &PORTD, 5}, // D5 23 + {&DDRE, &PINE, &PORTE, 6} // E6 24 +}; +//------------------------------------------------------------------------------ +#elif defined(__AVR_AT90USB646__)\ +|| defined(__AVR_AT90USB1286__) +// Teensy++ 1.0 & 2.0 + +// Two Wire (aka I2C) ports +uint8_t const SDA_PIN = 1; // D1 +uint8_t const SCL_PIN = 0; // D0 + +// SPI port +uint8_t const SS_PIN = 20; // B0 +uint8_t const MOSI_PIN = 22; // B2 +uint8_t const MISO_PIN = 23; // B3 +uint8_t const SCK_PIN = 21; // B1 + +static const pin_map_t digitalPinMap[] = { + {&DDRD, &PIND, &PORTD, 0}, // D0 0 + {&DDRD, &PIND, &PORTD, 1}, // D1 1 + {&DDRD, &PIND, &PORTD, 2}, // D2 2 + {&DDRD, &PIND, &PORTD, 3}, // D3 3 + {&DDRD, &PIND, &PORTD, 4}, // D4 4 + {&DDRD, &PIND, &PORTD, 5}, // D5 5 + {&DDRD, &PIND, &PORTD, 6}, // D6 6 + {&DDRD, &PIND, &PORTD, 7}, // D7 7 + {&DDRE, &PINE, &PORTE, 0}, // E0 8 + {&DDRE, &PINE, &PORTE, 1}, // E1 9 + {&DDRC, &PINC, &PORTC, 0}, // C0 10 + {&DDRC, &PINC, &PORTC, 1}, // C1 11 + {&DDRC, &PINC, &PORTC, 2}, // C2 12 + {&DDRC, &PINC, &PORTC, 3}, // C3 13 + {&DDRC, &PINC, &PORTC, 4}, // C4 14 + {&DDRC, &PINC, &PORTC, 5}, // C5 15 + {&DDRC, &PINC, &PORTC, 6}, // C6 16 + {&DDRC, &PINC, &PORTC, 7}, // C7 17 + {&DDRE, &PINE, &PORTE, 6}, // E6 18 + {&DDRE, &PINE, &PORTE, 7}, // E7 19 + {&DDRB, &PINB, &PORTB, 0}, // B0 20 + {&DDRB, &PINB, &PORTB, 1}, // B1 21 + {&DDRB, &PINB, &PORTB, 2}, // B2 22 + {&DDRB, &PINB, &PORTB, 3}, // B3 23 + {&DDRB, &PINB, &PORTB, 4}, // B4 24 + {&DDRB, &PINB, &PORTB, 5}, // B5 25 + {&DDRB, &PINB, &PORTB, 6}, // B6 26 + {&DDRB, &PINB, &PORTB, 7}, // B7 27 + {&DDRA, &PINA, &PORTA, 0}, // A0 28 + {&DDRA, &PINA, &PORTA, 1}, // A1 29 + {&DDRA, &PINA, &PORTA, 2}, // A2 30 + {&DDRA, &PINA, &PORTA, 3}, // A3 31 + {&DDRA, &PINA, &PORTA, 4}, // A4 32 + {&DDRA, &PINA, &PORTA, 5}, // A5 33 + {&DDRA, &PINA, &PORTA, 6}, // A6 34 + {&DDRA, &PINA, &PORTA, 7}, // A7 35 + {&DDRE, &PINE, &PORTE, 4}, // E4 36 + {&DDRE, &PINE, &PORTE, 5}, // E5 37 + {&DDRF, &PINF, &PORTF, 0}, // F0 38 + {&DDRF, &PINF, &PORTF, 1}, // F1 39 + {&DDRF, &PINF, &PORTF, 2}, // F2 40 + {&DDRF, &PINF, &PORTF, 3}, // F3 41 + {&DDRF, &PINF, &PORTF, 4}, // F4 42 + {&DDRF, &PINF, &PORTF, 5}, // F5 43 + {&DDRF, &PINF, &PORTF, 6}, // F6 44 + {&DDRF, &PINF, &PORTF, 7} // F7 45 +}; +//------------------------------------------------------------------------------ +#elif defined(__AVR_ATmega168__)\ +||defined(__AVR_ATmega168P__)\ +||defined(__AVR_ATmega328P__) +// 168 and 328 Arduinos + +// Two Wire (aka I2C) ports +uint8_t const SDA_PIN = 18; // C4 +uint8_t const SCL_PIN = 19; // C5 + +// SPI port +uint8_t const SS_PIN = 10; // B2 +uint8_t const MOSI_PIN = 11; // B3 +uint8_t const MISO_PIN = 12; // B4 +uint8_t const SCK_PIN = 13; // B5 + +static const pin_map_t digitalPinMap[] = { + {&DDRD, &PIND, &PORTD, 0}, // D0 0 + {&DDRD, &PIND, &PORTD, 1}, // D1 1 + {&DDRD, &PIND, &PORTD, 2}, // D2 2 + {&DDRD, &PIND, &PORTD, 3}, // D3 3 + {&DDRD, &PIND, &PORTD, 4}, // D4 4 + {&DDRD, &PIND, &PORTD, 5}, // D5 5 + {&DDRD, &PIND, &PORTD, 6}, // D6 6 + {&DDRD, &PIND, &PORTD, 7}, // D7 7 + {&DDRB, &PINB, &PORTB, 0}, // B0 8 + {&DDRB, &PINB, &PORTB, 1}, // B1 9 + {&DDRB, &PINB, &PORTB, 2}, // B2 10 + {&DDRB, &PINB, &PORTB, 3}, // B3 11 + {&DDRB, &PINB, &PORTB, 4}, // B4 12 + {&DDRB, &PINB, &PORTB, 5}, // B5 13 + {&DDRC, &PINC, &PORTC, 0}, // C0 14 + {&DDRC, &PINC, &PORTC, 1}, // C1 15 + {&DDRC, &PINC, &PORTC, 2}, // C2 16 + {&DDRC, &PINC, &PORTC, 3}, // C3 17 + {&DDRC, &PINC, &PORTC, 4}, // C4 18 + {&DDRC, &PINC, &PORTC, 5} // C5 19 +}; +#else // defined(__AVR_ATmega1280__) +#error unknown chip +#endif // defined(__AVR_ATmega1280__) +//------------------------------------------------------------------------------ +static const uint8_t digitalPinCount = sizeof(digitalPinMap)/sizeof(pin_map_t); + +uint8_t badPinNumber(void) + __attribute__((error("Pin number is too large or not a constant"))); + +static inline __attribute__((always_inline)) + bool getPinMode(uint8_t pin) { + if (__builtin_constant_p(pin) && pin < digitalPinCount) { + return (*digitalPinMap[pin].ddr >> digitalPinMap[pin].bit) & 1; + } else { + return badPinNumber(); + } +} +static inline __attribute__((always_inline)) + void setPinMode(uint8_t pin, uint8_t mode) { + if (__builtin_constant_p(pin) && pin < digitalPinCount) { + if (mode) { + *digitalPinMap[pin].ddr |= 1 << digitalPinMap[pin].bit; + } else { + *digitalPinMap[pin].ddr &= ~(1 << digitalPinMap[pin].bit); + } + } else { + badPinNumber(); + } +} +static inline __attribute__((always_inline)) + bool fastDigitalRead(uint8_t pin) { + if (__builtin_constant_p(pin) && pin < digitalPinCount) { + return (*digitalPinMap[pin].pin >> digitalPinMap[pin].bit) & 1; + } else { + return badPinNumber(); + } +} +static inline __attribute__((always_inline)) + void fastDigitalWrite(uint8_t pin, uint8_t value) { + if (__builtin_constant_p(pin) && pin < digitalPinCount) { + if (value) { + *digitalPinMap[pin].port |= 1 << digitalPinMap[pin].bit; + } else { + *digitalPinMap[pin].port &= ~(1 << digitalPinMap[pin].bit); + } + } else { + badPinNumber(); + } +} +#endif // Sd2PinMap_h + + #endif \ No newline at end of file diff --git a/Firmware/SdBaseFile.h b/Firmware/SdBaseFile.h index ab73bf638..923a391dd 100644 --- a/Firmware/SdBaseFile.h +++ b/Firmware/SdBaseFile.h @@ -31,7 +31,7 @@ #include "SdVolume.h" //------------------------------------------------------------------------------ /** - * \struct fpos_t + * \struct filepos_t * \brief internal type for istream * do not use in user apps */ diff --git a/Firmware/SdFatUtil.h b/Firmware/SdFatUtil.h index 8a6957bfa..c42b74b1c 100644 --- a/Firmware/SdFatUtil.h +++ b/Firmware/SdFatUtil.h @@ -1,51 +1,51 @@ -/* Arduino SdFat Library - * Copyright (C) 2008 by William Greiman - * - * This file is part of the Arduino SdFat Library - * - * This Library is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This Library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with the Arduino SdFat Library. If not, see - * . - */ -#include "Marlin.h" -#ifdef SDSUPPORT - -#ifndef SdFatUtil_h -#define SdFatUtil_h -/** - * \file - * \brief Useful utility functions. - */ -#include "Marlin.h" -#include "MarlinSerial.h" -/** Store and print a string in flash memory.*/ -#define PgmPrint(x) SerialPrint_P(PSTR(x)) -/** Store and print a string in flash memory followed by a CR/LF.*/ -#define PgmPrintln(x) SerialPrintln_P(PSTR(x)) - -namespace SdFatUtil { - int FreeRam(); - void print_P( PGM_P str); - void println_P( PGM_P str); - void SerialPrint_P(PGM_P str); - void SerialPrintln_P(PGM_P str); - void set_stack_guard(); - bool test_stack_integrity(); - uint32_t get_stack_guard_test_value(); -} - -using namespace SdFatUtil; // NOLINT -#endif // #define SdFatUtil_h - - +/* Arduino SdFat Library + * Copyright (C) 2008 by William Greiman + * + * This file is part of the Arduino SdFat Library + * + * This Library is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This Library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with the Arduino SdFat Library. If not, see + * . + */ +#include "Marlin.h" +#ifdef SDSUPPORT + +#ifndef SdFatUtil_h +#define SdFatUtil_h +/** + * \file + * \brief Useful utility functions. + */ +#include "Marlin.h" +#include "MarlinSerial.h" +/** Store and print a string in flash memory.*/ +#define PgmPrint(x) SerialPrint_P(PSTR(x)) +/** Store and print a string in flash memory followed by a CR/LF.*/ +#define PgmPrintln(x) SerialPrintln_P(PSTR(x)) + +namespace SdFatUtil { + int FreeRam(); + void print_P( PGM_P str); + void println_P( PGM_P str); + void SerialPrint_P(PGM_P str); + void SerialPrintln_P(PGM_P str); + void set_stack_guard(); + bool test_stack_integrity(); + uint32_t get_stack_guard_test_value(); +} + +using namespace SdFatUtil; // NOLINT +#endif // #define SdFatUtil_h + + #endif \ No newline at end of file diff --git a/Firmware/SdFile.cpp b/Firmware/SdFile.cpp index 29f5efadc..2fb4d5943 100644 --- a/Firmware/SdFile.cpp +++ b/Firmware/SdFile.cpp @@ -1,95 +1,95 @@ -/* Arduino SdFat Library - * Copyright (C) 2009 by William Greiman - * - * This file is part of the Arduino SdFat Library - * - * This Library is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This Library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the Arduino SdFat Library. If not, see - * . - */ -#include "Marlin.h" - -#ifdef SDSUPPORT -#include "SdFile.h" -/** Create a file object and open it in the current working directory. - * - * \param[in] path A path with a valid 8.3 DOS name for a file to be opened. - * - * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive - * OR of open flags. see SdBaseFile::open(SdBaseFile*, const char*, uint8_t). - */ -SdFile::SdFile(const char* path, uint8_t oflag) : SdBaseFile(path, oflag) { -} -//------------------------------------------------------------------------------ -/** Write data to an open file. - * - * \note Data is moved to the cache but may not be written to the - * storage device until sync() is called. - * - * \param[in] buf Pointer to the location of the data to be written. - * - * \param[in] nbyte Number of bytes to write. - * - * \return For success write() returns the number of bytes written, always - * \a nbyte. If an error occurs, write() returns -1. Possible errors - * include write() is called before a file has been opened, write is called - * for a read-only file, device is full, a corrupt file system or an I/O error. - * - */ -int16_t SdFile::write(const void* buf, uint16_t nbyte) { - return SdBaseFile::write(buf, nbyte); -} -//------------------------------------------------------------------------------ -/** Write a byte to a file. Required by the Arduino Print class. - * \param[in] b the byte to be written. - * Use writeError to check for errors. - */ -#if ARDUINO >= 100 -size_t SdFile::write(uint8_t b) -{ - return SdBaseFile::write(&b, 1); -} -#else -void SdFile::write(uint8_t b) -{ - SdBaseFile::write(&b, 1); -} -#endif -//------------------------------------------------------------------------------ -/** Write a string to a file. Used by the Arduino Print class. - * \param[in] str Pointer to the string. - * Use writeError to check for errors. - */ -void SdFile::write(const char* str) { - SdBaseFile::write(str, strlen(str)); -} -//------------------------------------------------------------------------------ -/** Write a PROGMEM string to a file. - * \param[in] str Pointer to the PROGMEM string. - * Use writeError to check for errors. - */ -void SdFile::write_P(PGM_P str) { - for (uint8_t c; (c = pgm_read_byte(str)); str++) write(c); -} -//------------------------------------------------------------------------------ -/** Write a PROGMEM string followed by CR/LF to a file. - * \param[in] str Pointer to the PROGMEM string. - * Use writeError to check for errors. - */ -void SdFile::writeln_P(PGM_P str) { - write_P(str); - write_P(PSTR("\r\n")); -} - - -#endif +/* Arduino SdFat Library + * Copyright (C) 2009 by William Greiman + * + * This file is part of the Arduino SdFat Library + * + * This Library is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This Library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Arduino SdFat Library. If not, see + * . + */ +#include "Marlin.h" + +#ifdef SDSUPPORT +#include "SdFile.h" +/** Create a file object and open it in the current working directory. + * + * \param[in] path A path with a valid 8.3 DOS name for a file to be opened. + * + * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive + * OR of open flags. see SdBaseFile::open(SdBaseFile*, const char*, uint8_t). + */ +SdFile::SdFile(const char* path, uint8_t oflag) : SdBaseFile(path, oflag) { +} +//------------------------------------------------------------------------------ +/** Write data to an open file. + * + * \note Data is moved to the cache but may not be written to the + * storage device until sync() is called. + * + * \param[in] buf Pointer to the location of the data to be written. + * + * \param[in] nbyte Number of bytes to write. + * + * \return For success write() returns the number of bytes written, always + * \a nbyte. If an error occurs, write() returns -1. Possible errors + * include write() is called before a file has been opened, write is called + * for a read-only file, device is full, a corrupt file system or an I/O error. + * + */ +int16_t SdFile::write(const void* buf, uint16_t nbyte) { + return SdBaseFile::write(buf, nbyte); +} +//------------------------------------------------------------------------------ +/** Write a byte to a file. Required by the Arduino Print class. + * \param[in] b the byte to be written. + * Use writeError to check for errors. + */ +#if ARDUINO >= 100 +size_t SdFile::write(uint8_t b) +{ + return SdBaseFile::write(&b, 1); +} +#else +void SdFile::write(uint8_t b) +{ + SdBaseFile::write(&b, 1); +} +#endif +//------------------------------------------------------------------------------ +/** Write a string to a file. Used by the Arduino Print class. + * \param[in] str Pointer to the string. + * Use writeError to check for errors. + */ +void SdFile::write(const char* str) { + SdBaseFile::write(str, strlen(str)); +} +//------------------------------------------------------------------------------ +/** Write a PROGMEM string to a file. + * \param[in] str Pointer to the PROGMEM string. + * Use writeError to check for errors. + */ +void SdFile::write_P(PGM_P str) { + for (uint8_t c; (c = pgm_read_byte(str)); str++) write(c); +} +//------------------------------------------------------------------------------ +/** Write a PROGMEM string followed by CR/LF to a file. + * \param[in] str Pointer to the PROGMEM string. + * Use writeError to check for errors. + */ +void SdFile::writeln_P(PGM_P str) { + write_P(str); + write_P(PSTR("\r\n")); +} + + +#endif diff --git a/Firmware/SdInfo.h b/Firmware/SdInfo.h index ea3108358..93f094314 100644 --- a/Firmware/SdInfo.h +++ b/Firmware/SdInfo.h @@ -1,286 +1,286 @@ -/* Arduino Sd2Card Library - * Copyright (C) 2009 by William Greiman - * - * This file is part of the Arduino Sd2Card Library - * - * This Library is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This Library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the Arduino Sd2Card Library. If not, see - * . - */ -#include "Marlin.h" -#ifdef SDSUPPORT - -#ifndef SdInfo_h -#define SdInfo_h -#include -// Based on the document: -// -// SD Specifications -// Part 1 -// Physical Layer -// Simplified Specification -// Version 3.01 -// May 18, 2010 -// -// http://www.sdcard.org/developers/tech/sdcard/pls/simplified_specs -//------------------------------------------------------------------------------ -// SD card commands -/** GO_IDLE_STATE - init card in spi mode if CS low */ -uint8_t const CMD0 = 0X00; -/** SEND_IF_COND - verify SD Memory Card interface operating condition.*/ -uint8_t const CMD8 = 0X08; -/** SEND_CSD - read the Card Specific Data (CSD register) */ -uint8_t const CMD9 = 0X09; -/** SEND_CID - read the card identification information (CID register) */ -uint8_t const CMD10 = 0X0A; -/** STOP_TRANSMISSION - end multiple block read sequence */ -uint8_t const CMD12 = 0X0C; -/** SEND_STATUS - read the card status register */ -uint8_t const CMD13 = 0X0D; -/** READ_SINGLE_BLOCK - read a single data block from the card */ -uint8_t const CMD17 = 0X11; -/** READ_MULTIPLE_BLOCK - read a multiple data blocks from the card */ -uint8_t const CMD18 = 0X12; -/** WRITE_BLOCK - write a single data block to the card */ -uint8_t const CMD24 = 0X18; -/** WRITE_MULTIPLE_BLOCK - write blocks of data until a STOP_TRANSMISSION */ -uint8_t const CMD25 = 0X19; -/** ERASE_WR_BLK_START - sets the address of the first block to be erased */ -uint8_t const CMD32 = 0X20; -/** ERASE_WR_BLK_END - sets the address of the last block of the continuous - range to be erased*/ -uint8_t const CMD33 = 0X21; -/** ERASE - erase all previously selected blocks */ -uint8_t const CMD38 = 0X26; - -/** Toshiba FlashAir: iSDIO */ -uint8_t const CMD48 = 0x30; -/** Toshiba FlashAir: iSDIO */ -uint8_t const CMD49 = 0x31; - -/** APP_CMD - escape for application specific command */ -uint8_t const CMD55 = 0X37; -/** READ_OCR - read the OCR register of a card */ -uint8_t const CMD58 = 0X3A; -/** SET_WR_BLK_ERASE_COUNT - Set the number of write blocks to be - pre-erased before writing */ -uint8_t const ACMD23 = 0X17; -/** SD_SEND_OP_COMD - Sends host capacity support information and - activates the card's initialization process */ -uint8_t const ACMD41 = 0X29; -//------------------------------------------------------------------------------ -/** status for card in the ready state */ -uint8_t const R1_READY_STATE = 0X00; -/** status for card in the idle state */ -uint8_t const R1_IDLE_STATE = 0X01; -/** status bit for illegal command */ -uint8_t const R1_ILLEGAL_COMMAND = 0X04; -/** start data token for read or write single block*/ -uint8_t const DATA_START_BLOCK = 0XFE; -/** stop token for write multiple blocks*/ -uint8_t const STOP_TRAN_TOKEN = 0XFD; -/** start data token for write multiple blocks*/ -uint8_t const WRITE_MULTIPLE_TOKEN = 0XFC; -/** mask for data response tokens after a write block operation */ -uint8_t const DATA_RES_MASK = 0X1F; -/** write data accepted token */ -uint8_t const DATA_RES_ACCEPTED = 0X05; -//------------------------------------------------------------------------------ -/** Card IDentification (CID) register */ -typedef struct CID { - // byte 0 - /** Manufacturer ID */ - unsigned char mid; - // byte 1-2 - /** OEM/Application ID */ - char oid[2]; - // byte 3-7 - /** Product name */ - char pnm[5]; - // byte 8 - /** Product revision least significant digit */ - unsigned char prv_m : 4; - /** Product revision most significant digit */ - unsigned char prv_n : 4; - // byte 9-12 - /** Product serial number */ - uint32_t psn; - // byte 13 - /** Manufacturing date year low digit */ - unsigned char mdt_year_high : 4; - /** not used */ - unsigned char reserved : 4; - // byte 14 - /** Manufacturing date month */ - unsigned char mdt_month : 4; - /** Manufacturing date year low digit */ - unsigned char mdt_year_low :4; - // byte 15 - /** not used always 1 */ - unsigned char always1 : 1; - /** CRC7 checksum */ - unsigned char crc : 7; -}cid_t; -//------------------------------------------------------------------------------ -/** CSD for version 1.00 cards */ -typedef struct CSDV1 { - // byte 0 - unsigned char reserved1 : 6; - unsigned char csd_ver : 2; - // byte 1 - unsigned char taac; - // byte 2 - unsigned char nsac; - // byte 3 - unsigned char tran_speed; - // byte 4 - unsigned char ccc_high; - // byte 5 - unsigned char read_bl_len : 4; - unsigned char ccc_low : 4; - // byte 6 - unsigned char c_size_high : 2; - unsigned char reserved2 : 2; - unsigned char dsr_imp : 1; - unsigned char read_blk_misalign :1; - unsigned char write_blk_misalign : 1; - unsigned char read_bl_partial : 1; - // byte 7 - unsigned char c_size_mid; - // byte 8 - unsigned char vdd_r_curr_max : 3; - unsigned char vdd_r_curr_min : 3; - unsigned char c_size_low :2; - // byte 9 - unsigned char c_size_mult_high : 2; - unsigned char vdd_w_cur_max : 3; - unsigned char vdd_w_curr_min : 3; - // byte 10 - unsigned char sector_size_high : 6; - unsigned char erase_blk_en : 1; - unsigned char c_size_mult_low : 1; - // byte 11 - unsigned char wp_grp_size : 7; - unsigned char sector_size_low : 1; - // byte 12 - unsigned char write_bl_len_high : 2; - unsigned char r2w_factor : 3; - unsigned char reserved3 : 2; - unsigned char wp_grp_enable : 1; - // byte 13 - unsigned char reserved4 : 5; - unsigned char write_partial : 1; - unsigned char write_bl_len_low : 2; - // byte 14 - unsigned char reserved5: 2; - unsigned char file_format : 2; - unsigned char tmp_write_protect : 1; - unsigned char perm_write_protect : 1; - unsigned char copy : 1; - /** Indicates the file format on the card */ - unsigned char file_format_grp : 1; - // byte 15 - unsigned char always1 : 1; - unsigned char crc : 7; -}csd1_t; -//------------------------------------------------------------------------------ -/** CSD for version 2.00 cards */ -typedef struct CSDV2 { - // byte 0 - unsigned char reserved1 : 6; - unsigned char csd_ver : 2; - // byte 1 - /** fixed to 0X0E */ - unsigned char taac; - // byte 2 - /** fixed to 0 */ - unsigned char nsac; - // byte 3 - unsigned char tran_speed; - // byte 4 - unsigned char ccc_high; - // byte 5 - /** This field is fixed to 9h, which indicates READ_BL_LEN=512 Byte */ - unsigned char read_bl_len : 4; - unsigned char ccc_low : 4; - // byte 6 - /** not used */ - unsigned char reserved2 : 4; - unsigned char dsr_imp : 1; - /** fixed to 0 */ - unsigned char read_blk_misalign :1; - /** fixed to 0 */ - unsigned char write_blk_misalign : 1; - /** fixed to 0 - no partial read */ - unsigned char read_bl_partial : 1; - // byte 7 - /** not used */ - unsigned char reserved3 : 2; - /** high part of card size */ - unsigned char c_size_high : 6; - // byte 8 - /** middle part of card size */ - unsigned char c_size_mid; - // byte 9 - /** low part of card size */ - unsigned char c_size_low; - // byte 10 - /** sector size is fixed at 64 KB */ - unsigned char sector_size_high : 6; - /** fixed to 1 - erase single is supported */ - unsigned char erase_blk_en : 1; - /** not used */ - unsigned char reserved4 : 1; - // byte 11 - unsigned char wp_grp_size : 7; - /** sector size is fixed at 64 KB */ - unsigned char sector_size_low : 1; - // byte 12 - /** write_bl_len fixed for 512 byte blocks */ - unsigned char write_bl_len_high : 2; - /** fixed value of 2 */ - unsigned char r2w_factor : 3; - /** not used */ - unsigned char reserved5 : 2; - /** fixed value of 0 - no write protect groups */ - unsigned char wp_grp_enable : 1; - // byte 13 - unsigned char reserved6 : 5; - /** always zero - no partial block read*/ - unsigned char write_partial : 1; - /** write_bl_len fixed for 512 byte blocks */ - unsigned char write_bl_len_low : 2; - // byte 14 - unsigned char reserved7: 2; - /** Do not use always 0 */ - unsigned char file_format : 2; - unsigned char tmp_write_protect : 1; - unsigned char perm_write_protect : 1; - unsigned char copy : 1; - /** Do not use always 0 */ - unsigned char file_format_grp : 1; - // byte 15 - /** not used always 1 */ - unsigned char always1 : 1; - /** checksum */ - unsigned char crc : 7; -}csd2_t; -//------------------------------------------------------------------------------ -/** union of old and new style CSD register */ -union csd_t { - csd1_t v1; - csd2_t v2; -}; -#endif // SdInfo_h - +/* Arduino Sd2Card Library + * Copyright (C) 2009 by William Greiman + * + * This file is part of the Arduino Sd2Card Library + * + * This Library is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This Library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Arduino Sd2Card Library. If not, see + * . + */ +#include "Marlin.h" +#ifdef SDSUPPORT + +#ifndef SdInfo_h +#define SdInfo_h +#include +// Based on the document: +// +// SD Specifications +// Part 1 +// Physical Layer +// Simplified Specification +// Version 3.01 +// May 18, 2010 +// +// http://www.sdcard.org/developers/tech/sdcard/pls/simplified_specs +//------------------------------------------------------------------------------ +// SD card commands +/** GO_IDLE_STATE - init card in spi mode if CS low */ +uint8_t const CMD0 = 0X00; +/** SEND_IF_COND - verify SD Memory Card interface operating condition.*/ +uint8_t const CMD8 = 0X08; +/** SEND_CSD - read the Card Specific Data (CSD register) */ +uint8_t const CMD9 = 0X09; +/** SEND_CID - read the card identification information (CID register) */ +uint8_t const CMD10 = 0X0A; +/** STOP_TRANSMISSION - end multiple block read sequence */ +uint8_t const CMD12 = 0X0C; +/** SEND_STATUS - read the card status register */ +uint8_t const CMD13 = 0X0D; +/** READ_SINGLE_BLOCK - read a single data block from the card */ +uint8_t const CMD17 = 0X11; +/** READ_MULTIPLE_BLOCK - read a multiple data blocks from the card */ +uint8_t const CMD18 = 0X12; +/** WRITE_BLOCK - write a single data block to the card */ +uint8_t const CMD24 = 0X18; +/** WRITE_MULTIPLE_BLOCK - write blocks of data until a STOP_TRANSMISSION */ +uint8_t const CMD25 = 0X19; +/** ERASE_WR_BLK_START - sets the address of the first block to be erased */ +uint8_t const CMD32 = 0X20; +/** ERASE_WR_BLK_END - sets the address of the last block of the continuous + range to be erased*/ +uint8_t const CMD33 = 0X21; +/** ERASE - erase all previously selected blocks */ +uint8_t const CMD38 = 0X26; + +/** Toshiba FlashAir: iSDIO */ +uint8_t const CMD48 = 0x30; +/** Toshiba FlashAir: iSDIO */ +uint8_t const CMD49 = 0x31; + +/** APP_CMD - escape for application specific command */ +uint8_t const CMD55 = 0X37; +/** READ_OCR - read the OCR register of a card */ +uint8_t const CMD58 = 0X3A; +/** SET_WR_BLK_ERASE_COUNT - Set the number of write blocks to be + pre-erased before writing */ +uint8_t const ACMD23 = 0X17; +/** SD_SEND_OP_COMD - Sends host capacity support information and + activates the card's initialization process */ +uint8_t const ACMD41 = 0X29; +//------------------------------------------------------------------------------ +/** status for card in the ready state */ +uint8_t const R1_READY_STATE = 0X00; +/** status for card in the idle state */ +uint8_t const R1_IDLE_STATE = 0X01; +/** status bit for illegal command */ +uint8_t const R1_ILLEGAL_COMMAND = 0X04; +/** start data token for read or write single block*/ +uint8_t const DATA_START_BLOCK = 0XFE; +/** stop token for write multiple blocks*/ +uint8_t const STOP_TRAN_TOKEN = 0XFD; +/** start data token for write multiple blocks*/ +uint8_t const WRITE_MULTIPLE_TOKEN = 0XFC; +/** mask for data response tokens after a write block operation */ +uint8_t const DATA_RES_MASK = 0X1F; +/** write data accepted token */ +uint8_t const DATA_RES_ACCEPTED = 0X05; +//------------------------------------------------------------------------------ +/** Card IDentification (CID) register */ +typedef struct CID { + // byte 0 + /** Manufacturer ID */ + unsigned char mid; + // byte 1-2 + /** OEM/Application ID */ + char oid[2]; + // byte 3-7 + /** Product name */ + char pnm[5]; + // byte 8 + /** Product revision least significant digit */ + unsigned char prv_m : 4; + /** Product revision most significant digit */ + unsigned char prv_n : 4; + // byte 9-12 + /** Product serial number */ + uint32_t psn; + // byte 13 + /** Manufacturing date year low digit */ + unsigned char mdt_year_high : 4; + /** not used */ + unsigned char reserved : 4; + // byte 14 + /** Manufacturing date month */ + unsigned char mdt_month : 4; + /** Manufacturing date year low digit */ + unsigned char mdt_year_low :4; + // byte 15 + /** not used always 1 */ + unsigned char always1 : 1; + /** CRC7 checksum */ + unsigned char crc : 7; +}cid_t; +//------------------------------------------------------------------------------ +/** CSD for version 1.00 cards */ +typedef struct CSDV1 { + // byte 0 + unsigned char reserved1 : 6; + unsigned char csd_ver : 2; + // byte 1 + unsigned char taac; + // byte 2 + unsigned char nsac; + // byte 3 + unsigned char tran_speed; + // byte 4 + unsigned char ccc_high; + // byte 5 + unsigned char read_bl_len : 4; + unsigned char ccc_low : 4; + // byte 6 + unsigned char c_size_high : 2; + unsigned char reserved2 : 2; + unsigned char dsr_imp : 1; + unsigned char read_blk_misalign :1; + unsigned char write_blk_misalign : 1; + unsigned char read_bl_partial : 1; + // byte 7 + unsigned char c_size_mid; + // byte 8 + unsigned char vdd_r_curr_max : 3; + unsigned char vdd_r_curr_min : 3; + unsigned char c_size_low :2; + // byte 9 + unsigned char c_size_mult_high : 2; + unsigned char vdd_w_cur_max : 3; + unsigned char vdd_w_curr_min : 3; + // byte 10 + unsigned char sector_size_high : 6; + unsigned char erase_blk_en : 1; + unsigned char c_size_mult_low : 1; + // byte 11 + unsigned char wp_grp_size : 7; + unsigned char sector_size_low : 1; + // byte 12 + unsigned char write_bl_len_high : 2; + unsigned char r2w_factor : 3; + unsigned char reserved3 : 2; + unsigned char wp_grp_enable : 1; + // byte 13 + unsigned char reserved4 : 5; + unsigned char write_partial : 1; + unsigned char write_bl_len_low : 2; + // byte 14 + unsigned char reserved5: 2; + unsigned char file_format : 2; + unsigned char tmp_write_protect : 1; + unsigned char perm_write_protect : 1; + unsigned char copy : 1; + /** Indicates the file format on the card */ + unsigned char file_format_grp : 1; + // byte 15 + unsigned char always1 : 1; + unsigned char crc : 7; +}csd1_t; +//------------------------------------------------------------------------------ +/** CSD for version 2.00 cards */ +typedef struct CSDV2 { + // byte 0 + unsigned char reserved1 : 6; + unsigned char csd_ver : 2; + // byte 1 + /** fixed to 0X0E */ + unsigned char taac; + // byte 2 + /** fixed to 0 */ + unsigned char nsac; + // byte 3 + unsigned char tran_speed; + // byte 4 + unsigned char ccc_high; + // byte 5 + /** This field is fixed to 9h, which indicates READ_BL_LEN=512 Byte */ + unsigned char read_bl_len : 4; + unsigned char ccc_low : 4; + // byte 6 + /** not used */ + unsigned char reserved2 : 4; + unsigned char dsr_imp : 1; + /** fixed to 0 */ + unsigned char read_blk_misalign :1; + /** fixed to 0 */ + unsigned char write_blk_misalign : 1; + /** fixed to 0 - no partial read */ + unsigned char read_bl_partial : 1; + // byte 7 + /** not used */ + unsigned char reserved3 : 2; + /** high part of card size */ + unsigned char c_size_high : 6; + // byte 8 + /** middle part of card size */ + unsigned char c_size_mid; + // byte 9 + /** low part of card size */ + unsigned char c_size_low; + // byte 10 + /** sector size is fixed at 64 KB */ + unsigned char sector_size_high : 6; + /** fixed to 1 - erase single is supported */ + unsigned char erase_blk_en : 1; + /** not used */ + unsigned char reserved4 : 1; + // byte 11 + unsigned char wp_grp_size : 7; + /** sector size is fixed at 64 KB */ + unsigned char sector_size_low : 1; + // byte 12 + /** write_bl_len fixed for 512 byte blocks */ + unsigned char write_bl_len_high : 2; + /** fixed value of 2 */ + unsigned char r2w_factor : 3; + /** not used */ + unsigned char reserved5 : 2; + /** fixed value of 0 - no write protect groups */ + unsigned char wp_grp_enable : 1; + // byte 13 + unsigned char reserved6 : 5; + /** always zero - no partial block read*/ + unsigned char write_partial : 1; + /** write_bl_len fixed for 512 byte blocks */ + unsigned char write_bl_len_low : 2; + // byte 14 + unsigned char reserved7: 2; + /** Do not use always 0 */ + unsigned char file_format : 2; + unsigned char tmp_write_protect : 1; + unsigned char perm_write_protect : 1; + unsigned char copy : 1; + /** Do not use always 0 */ + unsigned char file_format_grp : 1; + // byte 15 + /** not used always 1 */ + unsigned char always1 : 1; + /** checksum */ + unsigned char crc : 7; +}csd2_t; +//------------------------------------------------------------------------------ +/** union of old and new style CSD register */ +union csd_t { + csd1_t v1; + csd2_t v2; +}; +#endif // SdInfo_h + #endif \ No newline at end of file diff --git a/Firmware/SdVolume.cpp b/Firmware/SdVolume.cpp index f14d7bc70..9d6abf300 100644 --- a/Firmware/SdVolume.cpp +++ b/Firmware/SdVolume.cpp @@ -1,405 +1,405 @@ -/* Arduino SdFat Library - * Copyright (C) 2009 by William Greiman - * - * This file is part of the Arduino SdFat Library - * - * This Library is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This Library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the Arduino SdFat Library. If not, see - * . - */ -#include "Marlin.h" -#ifdef SDSUPPORT - -#include "SdVolume.h" -//------------------------------------------------------------------------------ -#if !USE_MULTIPLE_CARDS -// raw block cache -uint32_t SdVolume::cacheBlockNumber_; // current block number -cache_t SdVolume::cacheBuffer_; // 512 byte cache for Sd2Card -Sd2Card* SdVolume::sdCard_; // pointer to SD card object -bool SdVolume::cacheDirty_; // cacheFlush() will write block if true -uint32_t SdVolume::cacheMirrorBlock_; // mirror block for second FAT -#endif // USE_MULTIPLE_CARDS -//------------------------------------------------------------------------------ -// find a contiguous group of clusters -bool SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) { - // start of group - uint32_t bgnCluster; - // end of group - uint32_t endCluster; - // last cluster of FAT - uint32_t fatEnd = clusterCount_ + 1; - - // flag to save place to start next search - bool setStart; - - // set search start cluster - if (*curCluster) { - // try to make file contiguous - bgnCluster = *curCluster + 1; - - // don't save new start location - setStart = false; - } else { - // start at likely place for free cluster - bgnCluster = allocSearchStart_; - - // save next search start if one cluster - setStart = count == 1; - } - // end of group - endCluster = bgnCluster; - - // search the FAT for free clusters - for (uint32_t n = 0;; n++, endCluster++) { - // can't find space checked all clusters - if (n >= clusterCount_) goto fail; - - // past end - start from beginning of FAT - if (endCluster > fatEnd) { - bgnCluster = endCluster = 2; - } - uint32_t f; - if (!fatGet(endCluster, &f)) goto fail; - - if (f != 0) { - // cluster in use try next cluster as bgnCluster - bgnCluster = endCluster + 1; - } else if ((endCluster - bgnCluster + 1) == count) { - // done - found space - break; - } - } - // mark end of chain - if (!fatPutEOC(endCluster)) goto fail; - - // link clusters - while (endCluster > bgnCluster) { - if (!fatPut(endCluster - 1, endCluster)) goto fail; - endCluster--; - } - if (*curCluster != 0) { - // connect chains - if (!fatPut(*curCluster, bgnCluster)) goto fail; - } - // return first cluster number to caller - *curCluster = bgnCluster; - - // remember possible next free cluster - if (setStart) allocSearchStart_ = bgnCluster + 1; - - return true; - - fail: - return false; -} -//------------------------------------------------------------------------------ -bool SdVolume::cacheFlush() { - if (cacheDirty_) { - if (!sdCard_->writeBlock(cacheBlockNumber_, cacheBuffer_.data)) { - goto fail; - } - // mirror FAT tables - if (cacheMirrorBlock_) { - if (!sdCard_->writeBlock(cacheMirrorBlock_, cacheBuffer_.data)) { - goto fail; - } - cacheMirrorBlock_ = 0; - } - cacheDirty_ = 0; - } - return true; - - fail: - return false; -} -//------------------------------------------------------------------------------ -bool SdVolume::cacheRawBlock(uint32_t blockNumber, bool dirty) { - if (cacheBlockNumber_ != blockNumber) { - if (!cacheFlush()) goto fail; - if (!sdCard_->readBlock(blockNumber, cacheBuffer_.data)) goto fail; - cacheBlockNumber_ = blockNumber; - } - if (dirty) cacheDirty_ = true; - return true; - - fail: - return false; -} -//------------------------------------------------------------------------------ -// return the size in bytes of a cluster chain -bool SdVolume::chainSize(uint32_t cluster, uint32_t* size) { - uint32_t s = 0; - do { - if (!fatGet(cluster, &cluster)) goto fail; - s += 512UL << clusterSizeShift_; - } while (!isEOC(cluster)); - *size = s; - return true; - - fail: - return false; -} -//------------------------------------------------------------------------------ -// Fetch a FAT entry -bool SdVolume::fatGet(uint32_t cluster, uint32_t* value) { - uint32_t lba; - if (cluster > (clusterCount_ + 1)) goto fail; - if (FAT12_SUPPORT && fatType_ == 12) { - uint16_t index = cluster; - index += index >> 1; - lba = fatStartBlock_ + (index >> 9); - if (!cacheRawBlock(lba, CACHE_FOR_READ)) goto fail; - index &= 0X1FF; - uint16_t tmp = cacheBuffer_.data[index]; - index++; - if (index == 512) { - if (!cacheRawBlock(lba + 1, CACHE_FOR_READ)) goto fail; - index = 0; - } - tmp |= cacheBuffer_.data[index] << 8; - *value = cluster & 1 ? tmp >> 4 : tmp & 0XFFF; - return true; - } - if (fatType_ == 16) { - lba = fatStartBlock_ + (cluster >> 8); - } else if (fatType_ == 32) { - lba = fatStartBlock_ + (cluster >> 7); - } else { - goto fail; - } - if (lba != cacheBlockNumber_) { - if (!cacheRawBlock(lba, CACHE_FOR_READ)) goto fail; - } - if (fatType_ == 16) { - *value = cacheBuffer_.fat16[cluster & 0XFF]; - } else { - *value = cacheBuffer_.fat32[cluster & 0X7F] & FAT32MASK; - } - return true; - - fail: - return false; -} -//------------------------------------------------------------------------------ -// Store a FAT entry -bool SdVolume::fatPut(uint32_t cluster, uint32_t value) { - uint32_t lba; - // error if reserved cluster - if (cluster < 2) goto fail; - - // error if not in FAT - if (cluster > (clusterCount_ + 1)) goto fail; - - if (FAT12_SUPPORT && fatType_ == 12) { - uint16_t index = cluster; - index += index >> 1; - lba = fatStartBlock_ + (index >> 9); - if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail; - // mirror second FAT - if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_; - index &= 0X1FF; - uint8_t tmp = value; - if (cluster & 1) { - tmp = (cacheBuffer_.data[index] & 0XF) | tmp << 4; - } - cacheBuffer_.data[index] = tmp; - index++; - if (index == 512) { - lba++; - index = 0; - if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail; - // mirror second FAT - if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_; - } - tmp = value >> 4; - if (!(cluster & 1)) { - tmp = ((cacheBuffer_.data[index] & 0XF0)) | tmp >> 4; - } - cacheBuffer_.data[index] = tmp; - return true; - } - if (fatType_ == 16) { - lba = fatStartBlock_ + (cluster >> 8); - } else if (fatType_ == 32) { - lba = fatStartBlock_ + (cluster >> 7); - } else { - goto fail; - } - if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail; - // store entry - if (fatType_ == 16) { - cacheBuffer_.fat16[cluster & 0XFF] = value; - } else { - cacheBuffer_.fat32[cluster & 0X7F] = value; - } - // mirror second FAT - if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_; - return true; - - fail: - return false; -} -//------------------------------------------------------------------------------ -// free a cluster chain -bool SdVolume::freeChain(uint32_t cluster) { - uint32_t next; - - // clear free cluster location - allocSearchStart_ = 2; - - do { - if (!fatGet(cluster, &next)) goto fail; - - // free cluster - if (!fatPut(cluster, 0)) goto fail; - - cluster = next; - } while (!isEOC(cluster)); - - return true; - - fail: - return false; -} -//------------------------------------------------------------------------------ -/** Volume free space in clusters. - * - * \return Count of free clusters for success or -1 if an error occurs. - */ -int32_t SdVolume::freeClusterCount() { - uint32_t free = 0; - uint16_t n; - uint32_t todo = clusterCount_ + 2; - - if (fatType_ == 16) { - n = 256; - } else if (fatType_ == 32) { - n = 128; - } else { - // put FAT12 here - return -1; - } - - for (uint32_t lba = fatStartBlock_; todo; todo -= n, lba++) { - if (!cacheRawBlock(lba, CACHE_FOR_READ)) return -1; - if (todo < n) n = todo; - if (fatType_ == 16) { - for (uint16_t i = 0; i < n; i++) { - if (cacheBuffer_.fat16[i] == 0) free++; - } - } else { - for (uint16_t i = 0; i < n; i++) { - if (cacheBuffer_.fat32[i] == 0) free++; - } - } - } - return free; -} -//------------------------------------------------------------------------------ -/** Initialize a FAT volume. - * - * \param[in] dev The SD card where the volume is located. - * - * \param[in] part The partition to be used. Legal values for \a part are - * 1-4 to use the corresponding partition on a device formatted with - * a MBR, Master Boot Record, or zero if the device is formatted as - * a super floppy with the FAT boot sector in block zero. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. Reasons for - * failure include not finding a valid partition, not finding a valid - * FAT file system in the specified partition or an I/O error. - */ -bool SdVolume::init(Sd2Card* dev, uint8_t part) { - uint32_t totalBlocks; - uint32_t volumeStartBlock = 0; - fat32_boot_t* fbs; - - sdCard_ = dev; - fatType_ = 0; - allocSearchStart_ = 2; - cacheDirty_ = 0; // cacheFlush() will write block if true - cacheMirrorBlock_ = 0; - cacheBlockNumber_ = 0XFFFFFFFF; - - // if part == 0 assume super floppy with FAT boot sector in block zero - // if part > 0 assume mbr volume with partition table - if (part) { - if (part > 4)goto fail; - if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) goto fail; - part_t* p = &cacheBuffer_.mbr.part[part-1]; - if ((p->boot & 0X7F) !=0 || - p->totalSectors < 100 || - p->firstSector == 0) { - // not a valid partition - goto fail; - } - volumeStartBlock = p->firstSector; - } - if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) goto fail; - fbs = &cacheBuffer_.fbs32; - if (fbs->bytesPerSector != 512 || - fbs->fatCount == 0 || - fbs->reservedSectorCount == 0 || - fbs->sectorsPerCluster == 0) { - // not valid FAT volume - goto fail; - } - fatCount_ = fbs->fatCount; - blocksPerCluster_ = fbs->sectorsPerCluster; - // determine shift that is same as multiply by blocksPerCluster_ - clusterSizeShift_ = 0; - while (blocksPerCluster_ != (1 << clusterSizeShift_)) { - // error if not power of 2 - if (clusterSizeShift_++ > 7) goto fail; - } - blocksPerFat_ = fbs->sectorsPerFat16 ? - fbs->sectorsPerFat16 : fbs->sectorsPerFat32; - - fatStartBlock_ = volumeStartBlock + fbs->reservedSectorCount; - - // count for FAT16 zero for FAT32 - rootDirEntryCount_ = fbs->rootDirEntryCount; - - // directory start for FAT16 dataStart for FAT32 - rootDirStart_ = fatStartBlock_ + fbs->fatCount * blocksPerFat_; - - // data start for FAT16 and FAT32 - dataStartBlock_ = rootDirStart_ + ((32 * fbs->rootDirEntryCount + 511)/512); - - // total blocks for FAT16 or FAT32 - totalBlocks = fbs->totalSectors16 ? - fbs->totalSectors16 : fbs->totalSectors32; - // total data blocks - clusterCount_ = totalBlocks - (dataStartBlock_ - volumeStartBlock); - - // divide by cluster size to get cluster count - clusterCount_ >>= clusterSizeShift_; - - // FAT type is determined by cluster count - if (clusterCount_ < 4085) { - fatType_ = 12; - if (!FAT12_SUPPORT) goto fail; - } else if (clusterCount_ < 65525) { - fatType_ = 16; - } else { - rootDirStart_ = fbs->fat32RootCluster; - fatType_ = 32; - } - return true; - - fail: - return false; -} +/* Arduino SdFat Library + * Copyright (C) 2009 by William Greiman + * + * This file is part of the Arduino SdFat Library + * + * This Library is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This Library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Arduino SdFat Library. If not, see + * . + */ +#include "Marlin.h" +#ifdef SDSUPPORT + +#include "SdVolume.h" +//------------------------------------------------------------------------------ +#if !USE_MULTIPLE_CARDS +// raw block cache +uint32_t SdVolume::cacheBlockNumber_; // current block number +cache_t SdVolume::cacheBuffer_; // 512 byte cache for Sd2Card +Sd2Card* SdVolume::sdCard_; // pointer to SD card object +bool SdVolume::cacheDirty_; // cacheFlush() will write block if true +uint32_t SdVolume::cacheMirrorBlock_; // mirror block for second FAT +#endif // USE_MULTIPLE_CARDS +//------------------------------------------------------------------------------ +// find a contiguous group of clusters +bool SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) { + // start of group + uint32_t bgnCluster; + // end of group + uint32_t endCluster; + // last cluster of FAT + uint32_t fatEnd = clusterCount_ + 1; + + // flag to save place to start next search + bool setStart; + + // set search start cluster + if (*curCluster) { + // try to make file contiguous + bgnCluster = *curCluster + 1; + + // don't save new start location + setStart = false; + } else { + // start at likely place for free cluster + bgnCluster = allocSearchStart_; + + // save next search start if one cluster + setStart = count == 1; + } + // end of group + endCluster = bgnCluster; + + // search the FAT for free clusters + for (uint32_t n = 0;; n++, endCluster++) { + // can't find space checked all clusters + if (n >= clusterCount_) goto fail; + + // past end - start from beginning of FAT + if (endCluster > fatEnd) { + bgnCluster = endCluster = 2; + } + uint32_t f; + if (!fatGet(endCluster, &f)) goto fail; + + if (f != 0) { + // cluster in use try next cluster as bgnCluster + bgnCluster = endCluster + 1; + } else if ((endCluster - bgnCluster + 1) == count) { + // done - found space + break; + } + } + // mark end of chain + if (!fatPutEOC(endCluster)) goto fail; + + // link clusters + while (endCluster > bgnCluster) { + if (!fatPut(endCluster - 1, endCluster)) goto fail; + endCluster--; + } + if (*curCluster != 0) { + // connect chains + if (!fatPut(*curCluster, bgnCluster)) goto fail; + } + // return first cluster number to caller + *curCluster = bgnCluster; + + // remember possible next free cluster + if (setStart) allocSearchStart_ = bgnCluster + 1; + + return true; + + fail: + return false; +} +//------------------------------------------------------------------------------ +bool SdVolume::cacheFlush() { + if (cacheDirty_) { + if (!sdCard_->writeBlock(cacheBlockNumber_, cacheBuffer_.data)) { + goto fail; + } + // mirror FAT tables + if (cacheMirrorBlock_) { + if (!sdCard_->writeBlock(cacheMirrorBlock_, cacheBuffer_.data)) { + goto fail; + } + cacheMirrorBlock_ = 0; + } + cacheDirty_ = 0; + } + return true; + + fail: + return false; +} +//------------------------------------------------------------------------------ +bool SdVolume::cacheRawBlock(uint32_t blockNumber, bool dirty) { + if (cacheBlockNumber_ != blockNumber) { + if (!cacheFlush()) goto fail; + if (!sdCard_->readBlock(blockNumber, cacheBuffer_.data)) goto fail; + cacheBlockNumber_ = blockNumber; + } + if (dirty) cacheDirty_ = true; + return true; + + fail: + return false; +} +//------------------------------------------------------------------------------ +// return the size in bytes of a cluster chain +bool SdVolume::chainSize(uint32_t cluster, uint32_t* size) { + uint32_t s = 0; + do { + if (!fatGet(cluster, &cluster)) goto fail; + s += 512UL << clusterSizeShift_; + } while (!isEOC(cluster)); + *size = s; + return true; + + fail: + return false; +} +//------------------------------------------------------------------------------ +// Fetch a FAT entry +bool SdVolume::fatGet(uint32_t cluster, uint32_t* value) { + uint32_t lba; + if (cluster > (clusterCount_ + 1)) goto fail; + if (FAT12_SUPPORT && fatType_ == 12) { + uint16_t index = cluster; + index += index >> 1; + lba = fatStartBlock_ + (index >> 9); + if (!cacheRawBlock(lba, CACHE_FOR_READ)) goto fail; + index &= 0X1FF; + uint16_t tmp = cacheBuffer_.data[index]; + index++; + if (index == 512) { + if (!cacheRawBlock(lba + 1, CACHE_FOR_READ)) goto fail; + index = 0; + } + tmp |= cacheBuffer_.data[index] << 8; + *value = cluster & 1 ? tmp >> 4 : tmp & 0XFFF; + return true; + } + if (fatType_ == 16) { + lba = fatStartBlock_ + (cluster >> 8); + } else if (fatType_ == 32) { + lba = fatStartBlock_ + (cluster >> 7); + } else { + goto fail; + } + if (lba != cacheBlockNumber_) { + if (!cacheRawBlock(lba, CACHE_FOR_READ)) goto fail; + } + if (fatType_ == 16) { + *value = cacheBuffer_.fat16[cluster & 0XFF]; + } else { + *value = cacheBuffer_.fat32[cluster & 0X7F] & FAT32MASK; + } + return true; + + fail: + return false; +} +//------------------------------------------------------------------------------ +// Store a FAT entry +bool SdVolume::fatPut(uint32_t cluster, uint32_t value) { + uint32_t lba; + // error if reserved cluster + if (cluster < 2) goto fail; + + // error if not in FAT + if (cluster > (clusterCount_ + 1)) goto fail; + + if (FAT12_SUPPORT && fatType_ == 12) { + uint16_t index = cluster; + index += index >> 1; + lba = fatStartBlock_ + (index >> 9); + if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail; + // mirror second FAT + if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_; + index &= 0X1FF; + uint8_t tmp = value; + if (cluster & 1) { + tmp = (cacheBuffer_.data[index] & 0XF) | tmp << 4; + } + cacheBuffer_.data[index] = tmp; + index++; + if (index == 512) { + lba++; + index = 0; + if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail; + // mirror second FAT + if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_; + } + tmp = value >> 4; + if (!(cluster & 1)) { + tmp = ((cacheBuffer_.data[index] & 0XF0)) | tmp >> 4; + } + cacheBuffer_.data[index] = tmp; + return true; + } + if (fatType_ == 16) { + lba = fatStartBlock_ + (cluster >> 8); + } else if (fatType_ == 32) { + lba = fatStartBlock_ + (cluster >> 7); + } else { + goto fail; + } + if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail; + // store entry + if (fatType_ == 16) { + cacheBuffer_.fat16[cluster & 0XFF] = value; + } else { + cacheBuffer_.fat32[cluster & 0X7F] = value; + } + // mirror second FAT + if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_; + return true; + + fail: + return false; +} +//------------------------------------------------------------------------------ +// free a cluster chain +bool SdVolume::freeChain(uint32_t cluster) { + uint32_t next; + + // clear free cluster location + allocSearchStart_ = 2; + + do { + if (!fatGet(cluster, &next)) goto fail; + + // free cluster + if (!fatPut(cluster, 0)) goto fail; + + cluster = next; + } while (!isEOC(cluster)); + + return true; + + fail: + return false; +} +//------------------------------------------------------------------------------ +/** Volume free space in clusters. + * + * \return Count of free clusters for success or -1 if an error occurs. + */ +int32_t SdVolume::freeClusterCount() { + uint32_t free = 0; + uint16_t n; + uint32_t todo = clusterCount_ + 2; + + if (fatType_ == 16) { + n = 256; + } else if (fatType_ == 32) { + n = 128; + } else { + // put FAT12 here + return -1; + } + + for (uint32_t lba = fatStartBlock_; todo; todo -= n, lba++) { + if (!cacheRawBlock(lba, CACHE_FOR_READ)) return -1; + if (todo < n) n = todo; + if (fatType_ == 16) { + for (uint16_t i = 0; i < n; i++) { + if (cacheBuffer_.fat16[i] == 0) free++; + } + } else { + for (uint16_t i = 0; i < n; i++) { + if (cacheBuffer_.fat32[i] == 0) free++; + } + } + } + return free; +} +//------------------------------------------------------------------------------ +/** Initialize a FAT volume. + * + * \param[in] dev The SD card where the volume is located. + * + * \param[in] part The partition to be used. Legal values for \a part are + * 1-4 to use the corresponding partition on a device formatted with + * a MBR, Master Boot Record, or zero if the device is formatted as + * a super floppy with the FAT boot sector in block zero. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. Reasons for + * failure include not finding a valid partition, not finding a valid + * FAT file system in the specified partition or an I/O error. + */ +bool SdVolume::init(Sd2Card* dev, uint8_t part) { + uint32_t totalBlocks; + uint32_t volumeStartBlock = 0; + fat32_boot_t* fbs; + + sdCard_ = dev; + fatType_ = 0; + allocSearchStart_ = 2; + cacheDirty_ = 0; // cacheFlush() will write block if true + cacheMirrorBlock_ = 0; + cacheBlockNumber_ = 0XFFFFFFFF; + + // if part == 0 assume super floppy with FAT boot sector in block zero + // if part > 0 assume mbr volume with partition table + if (part) { + if (part > 4)goto fail; + if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) goto fail; + part_t* p = &cacheBuffer_.mbr.part[part-1]; + if ((p->boot & 0X7F) !=0 || + p->totalSectors < 100 || + p->firstSector == 0) { + // not a valid partition + goto fail; + } + volumeStartBlock = p->firstSector; + } + if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) goto fail; + fbs = &cacheBuffer_.fbs32; + if (fbs->bytesPerSector != 512 || + fbs->fatCount == 0 || + fbs->reservedSectorCount == 0 || + fbs->sectorsPerCluster == 0) { + // not valid FAT volume + goto fail; + } + fatCount_ = fbs->fatCount; + blocksPerCluster_ = fbs->sectorsPerCluster; + // determine shift that is same as multiply by blocksPerCluster_ + clusterSizeShift_ = 0; + while (blocksPerCluster_ != (1 << clusterSizeShift_)) { + // error if not power of 2 + if (clusterSizeShift_++ > 7) goto fail; + } + blocksPerFat_ = fbs->sectorsPerFat16 ? + fbs->sectorsPerFat16 : fbs->sectorsPerFat32; + + fatStartBlock_ = volumeStartBlock + fbs->reservedSectorCount; + + // count for FAT16 zero for FAT32 + rootDirEntryCount_ = fbs->rootDirEntryCount; + + // directory start for FAT16 dataStart for FAT32 + rootDirStart_ = fatStartBlock_ + fbs->fatCount * blocksPerFat_; + + // data start for FAT16 and FAT32 + dataStartBlock_ = rootDirStart_ + ((32 * fbs->rootDirEntryCount + 511)/512); + + // total blocks for FAT16 or FAT32 + totalBlocks = fbs->totalSectors16 ? + fbs->totalSectors16 : fbs->totalSectors32; + // total data blocks + clusterCount_ = totalBlocks - (dataStartBlock_ - volumeStartBlock); + + // divide by cluster size to get cluster count + clusterCount_ >>= clusterSizeShift_; + + // FAT type is determined by cluster count + if (clusterCount_ < 4085) { + fatType_ = 12; + if (!FAT12_SUPPORT) goto fail; + } else if (clusterCount_ < 65525) { + fatType_ = 16; + } else { + rootDirStart_ = fbs->fat32RootCluster; + fatType_ = 32; + } + return true; + + fail: + return false; +} #endif \ No newline at end of file diff --git a/Firmware/langtool.pl b/Firmware/langtool.pl index 96e3cb8fd..ac9dee72d 100644 --- a/Firmware/langtool.pl +++ b/Firmware/langtool.pl @@ -180,6 +180,7 @@ print $fh < // Language indices into their particular symbol tables. END ; @@ -242,7 +243,7 @@ $filename = 'language_all.cpp'; open($fh, '>', $filename) or die "Could not open file '$filename' $!"; print $fh <<'END' -#include + #include "Configuration_prusa.h" #include "language_all.h" diff --git a/Firmware/language_all.cpp b/Firmware/language_all.cpp index 3cdad48f0..9ba394cc9 100644 --- a/Firmware/language_all.cpp +++ b/Firmware/language_all.cpp @@ -1,4 +1,4 @@ -#include + #include "Configuration_prusa.h" #include "language_all.h" @@ -25,6 +25,21 @@ const char * const MSG_ADJUSTZ_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_ADJUSTZ_DE }; +const char MSG_ALL_EN[] PROGMEM = "All"; +const char MSG_ALL_CZ[] PROGMEM = "Vse"; +const char MSG_ALL_IT[] PROGMEM = "Tutti"; +const char MSG_ALL_ES[] PROGMEM = "Todos"; +const char MSG_ALL_PL[] PROGMEM = "Wszystko"; +const char MSG_ALL_DE[] PROGMEM = "Alle"; +const char * const MSG_ALL_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_ALL_EN, + MSG_ALL_CZ, + MSG_ALL_IT, + MSG_ALL_ES, + MSG_ALL_PL, + MSG_ALL_DE +}; + const char MSG_AMAX_EN[] PROGMEM = "Amax "; const char * const MSG_AMAX_LANG_TABLE[1] PROGMEM = { MSG_AMAX_EN @@ -121,12 +136,12 @@ const char * const MSG_BED_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_BED_EN }; -const char MSG_BED_CORRECTION_FRONT_EN[] PROGMEM = "Front side um"; +const char MSG_BED_CORRECTION_FRONT_EN[] PROGMEM = "Front side[um]"; const char MSG_BED_CORRECTION_FRONT_CZ[] PROGMEM = "Vpredu [um]"; -const char MSG_BED_CORRECTION_FRONT_IT[] PROGMEM = "Lato ateriore"; +const char MSG_BED_CORRECTION_FRONT_IT[] PROGMEM = "Fronte [um]"; const char MSG_BED_CORRECTION_FRONT_ES[] PROGMEM = "Adelante [um]"; const char MSG_BED_CORRECTION_FRONT_PL[] PROGMEM = "Do przodu [um]"; -const char MSG_BED_CORRECTION_FRONT_DE[] PROGMEM = "Vorderseite [um]"; +const char MSG_BED_CORRECTION_FRONT_DE[] PROGMEM = "Vorne [um]"; const char * const MSG_BED_CORRECTION_FRONT_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_BED_CORRECTION_FRONT_EN, MSG_BED_CORRECTION_FRONT_CZ, @@ -136,12 +151,12 @@ const char * const MSG_BED_CORRECTION_FRONT_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_BED_CORRECTION_FRONT_DE }; -const char MSG_BED_CORRECTION_LEFT_EN[] PROGMEM = "Left side um"; +const char MSG_BED_CORRECTION_LEFT_EN[] PROGMEM = "Left side [um]"; const char MSG_BED_CORRECTION_LEFT_CZ[] PROGMEM = "Vlevo [um]"; -const char MSG_BED_CORRECTION_LEFT_IT[] PROGMEM = "Lato sinistro"; +const char MSG_BED_CORRECTION_LEFT_IT[] PROGMEM = "Sinistra [um]"; const char MSG_BED_CORRECTION_LEFT_ES[] PROGMEM = "Izquierda [um]"; const char MSG_BED_CORRECTION_LEFT_PL[] PROGMEM = "W lewo [um]"; -const char MSG_BED_CORRECTION_LEFT_DE[] PROGMEM = "Linke Seite [um]"; +const char MSG_BED_CORRECTION_LEFT_DE[] PROGMEM = "Links [um]"; const char * const MSG_BED_CORRECTION_LEFT_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_BED_CORRECTION_LEFT_EN, MSG_BED_CORRECTION_LEFT_CZ, @@ -166,12 +181,12 @@ const char * const MSG_BED_CORRECTION_MENU_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_BED_CORRECTION_MENU_DE }; -const char MSG_BED_CORRECTION_REAR_EN[] PROGMEM = "Rear side um"; +const char MSG_BED_CORRECTION_REAR_EN[] PROGMEM = "Rear side [um]"; const char MSG_BED_CORRECTION_REAR_CZ[] PROGMEM = "Vzadu [um]"; -const char MSG_BED_CORRECTION_REAR_IT[] PROGMEM = "Lato posteriore"; +const char MSG_BED_CORRECTION_REAR_IT[] PROGMEM = "Retro [um]"; const char MSG_BED_CORRECTION_REAR_ES[] PROGMEM = "Atras [um]"; const char MSG_BED_CORRECTION_REAR_PL[] PROGMEM = "Do tylu [um]"; -const char MSG_BED_CORRECTION_REAR_DE[] PROGMEM = "Rueckseite [um]"; +const char MSG_BED_CORRECTION_REAR_DE[] PROGMEM = "Hinten [um]"; const char * const MSG_BED_CORRECTION_REAR_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_BED_CORRECTION_REAR_EN, MSG_BED_CORRECTION_REAR_CZ, @@ -182,16 +197,22 @@ const char * const MSG_BED_CORRECTION_REAR_LANG_TABLE[LANG_NUM] PROGMEM = { }; const char MSG_BED_CORRECTION_RESET_EN[] PROGMEM = "Reset"; -const char * const MSG_BED_CORRECTION_RESET_LANG_TABLE[1] PROGMEM = { - MSG_BED_CORRECTION_RESET_EN +const char MSG_BED_CORRECTION_RESET_DE[] PROGMEM = "Ruecksetzen"; +const char * const MSG_BED_CORRECTION_RESET_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_BED_CORRECTION_RESET_EN, + MSG_BED_CORRECTION_RESET_EN, + MSG_BED_CORRECTION_RESET_EN, + MSG_BED_CORRECTION_RESET_EN, + MSG_BED_CORRECTION_RESET_EN, + MSG_BED_CORRECTION_RESET_DE }; -const char MSG_BED_CORRECTION_RIGHT_EN[] PROGMEM = "Right side um"; +const char MSG_BED_CORRECTION_RIGHT_EN[] PROGMEM = "Right side[um]"; const char MSG_BED_CORRECTION_RIGHT_CZ[] PROGMEM = "Vpravo [um]"; -const char MSG_BED_CORRECTION_RIGHT_IT[] PROGMEM = "Lato destro"; +const char MSG_BED_CORRECTION_RIGHT_IT[] PROGMEM = "Destra [um]"; const char MSG_BED_CORRECTION_RIGHT_ES[] PROGMEM = "Derecha [um]"; const char MSG_BED_CORRECTION_RIGHT_PL[] PROGMEM = "W prawo [um]"; -const char MSG_BED_CORRECTION_RIGHT_DE[] PROGMEM = "Rechte Seite [um]"; +const char MSG_BED_CORRECTION_RIGHT_DE[] PROGMEM = "Rechts [um]"; const char * const MSG_BED_CORRECTION_RIGHT_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_BED_CORRECTION_RIGHT_EN, MSG_BED_CORRECTION_RIGHT_CZ, @@ -221,7 +242,7 @@ const char MSG_BED_HEATING_CZ[] PROGMEM = "Zahrivani bed"; const char MSG_BED_HEATING_IT[] PROGMEM = "Riscald. letto"; const char MSG_BED_HEATING_ES[] PROGMEM = "Calentando Base"; const char MSG_BED_HEATING_PL[] PROGMEM = "Grzanie stolika.."; -const char MSG_BED_HEATING_DE[] PROGMEM = "Bed erwaermen"; +const char MSG_BED_HEATING_DE[] PROGMEM = "Bed aufwaermen"; const char * const MSG_BED_HEATING_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_BED_HEATING_EN, MSG_BED_HEATING_CZ, @@ -251,7 +272,7 @@ const char MSG_BED_LEVELING_FAILED_POINT_LOW_CZ[] PROGMEM = "Kalibrace Z selhala const char MSG_BED_LEVELING_FAILED_POINT_LOW_IT[] PROGMEM = "Livellamento letto fallito.NoRispSensor Residui su ugello? In attesa di reset."; const char MSG_BED_LEVELING_FAILED_POINT_LOW_ES[] PROGMEM = "Nivelacion fallada. Sensor no funciona. Escombros en Boqui.? Esperando reset."; const char MSG_BED_LEVELING_FAILED_POINT_LOW_PL[] PROGMEM = "Kalibracja nieudana. Sensor nie dotknal. Zanieczysz. dysza? Czekam na reset."; -const char MSG_BED_LEVELING_FAILED_POINT_LOW_DE[] PROGMEM = "Z-Kal. fehlgeschlg. Sensor nicht ausgeloest. Schmutze Duese? Warte auf RST"; +const char MSG_BED_LEVELING_FAILED_POINT_LOW_DE[] PROGMEM = "Z-Kal. fehlgeschlg. Sensor nicht ausgeloest. Schmutzige Duese? Warte auf Reset"; const char * const MSG_BED_LEVELING_FAILED_POINT_LOW_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_BED_LEVELING_FAILED_POINT_LOW_EN, MSG_BED_LEVELING_FAILED_POINT_LOW_CZ, @@ -281,7 +302,7 @@ const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_CZ[] PROGMEM = "K const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_IT[] PROGMEM = "Calibrazione XYZ fallita. Punti anteriori non raggiungibili."; const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_ES[] PROGMEM = "Calibracion XYZ fallad. Punto delanteros no alcanzables."; const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_PL[] PROGMEM = "Kalibr. XYZ nieudana. Przed. punkty kalibr. zbyt do przodu. Wyrownac drukarke."; -const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_DE[] PROGMEM = "XYZ-Kalibrierung fehlgeschlagen. Vordere Kalibrierpunkte sind zu weit nach vorne."; +const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_DE[] PROGMEM = "XYZ-Kalibrierung fehlgeschlagen. Vordere Kalibrierpunkte sind zu weit vorne."; const char * const MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_EN, MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_CZ, @@ -296,7 +317,7 @@ const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_CZ[] PROGMEM = "K const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_IT[] PROGMEM = "Calibrazione XYZ fallita. Punto anteriore sinistro non raggiungibile."; const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_ES[] PROGMEM = "Calibracion XYZ fallad. Punto delantero izquierdo no alcanzable."; const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_PL[] PROGMEM = "Kalibr. XYZ nieudana. Lewy przedni punkt zbyt do przodu. Wyrownac drukarke."; -const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_DE[] PROGMEM = "XYZ-Kalibrierung fehlgeschlagen. Linker vorderer Kalibrierpunkt ist zu weit nach vorne."; +const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_DE[] PROGMEM = "XYZ-Kalibrierung fehlgeschlagen. Linker vorderer Kalibrierpunkt ist zu weit vorne."; const char * const MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_EN, MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_CZ, @@ -311,7 +332,7 @@ const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_CZ[] PROGMEM = " const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_IT[] PROGMEM = "Calibrazione XYZ fallita. Punto anteriore destro non raggiungibile."; const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_ES[] PROGMEM = "Calibracion XYZ fallad. Punto delantero derecho no alcanzable."; const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_PL[] PROGMEM = "Kalibr. XYZ nieudana. Prawy przedni punkt zbyt do przodu. Wyrownac drukarke."; -const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_DE[] PROGMEM = "XYZ-Kalibrierung fehlgeschlagen. Rechter vorderer Kalibrierpunkt ist zu weit nach vorne."; +const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_DE[] PROGMEM = "XYZ-Kalibrierung fehlgeschlagen. Rechter vorderer Kalibrierpunkt ist zu weit vorne."; const char * const MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_EN, MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_CZ, @@ -341,7 +362,7 @@ const char MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_CZ[] PROGMEM = "Kalibrace XYZ v const char MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_IT[] PROGMEM = "Calibrazione XYZ OK. Gli assi X/Y sono perpendicolari. Complimenti!"; const char MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_ES[] PROGMEM = "Calibracion XYZ ok. Ejes X/Y perpendiculares. Felicitaciones!"; const char MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_PL[] PROGMEM = "Kalibracja XYZ ok. Osie X/Y sa prostopadle. Gratulacje!"; -const char MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_DE[] PROGMEM = "XYZ-Kalibrierung ok. X/Y-Achsen sind im Lot. Glueckwunsch!"; +const char MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_DE[] PROGMEM = "XYZ-Kalibrierung ok. X/Y-Achsen sind senkrecht zueinander. Glueckwunsch!"; const char * const MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_EN, MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_CZ, @@ -401,7 +422,7 @@ const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_CZ[] PROGMEM = " const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_IT[] PROGMEM = "Calibrazione XYZ compromessa. Punti anteriori non raggiungibili."; const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_ES[] PROGMEM = "Calibrazion XYZ comprometida. Punto delanteros no alcanzables."; const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_PL[] PROGMEM = "Kalibr. XYZ niedokladna. Przednie punkty kalibr. Zbyt wys. do przodu."; -const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_DE[] PROGMEM = "XYZ-Kalibrierung ungenau. Vordere Kalibrierpunkte sind zu weit nach vorne."; +const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_DE[] PROGMEM = "XYZ-Kalibrierung ungenau. Vordere Kalibrierpunkte sind zu weit vorne."; const char * const MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_EN, MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_CZ, @@ -416,7 +437,7 @@ const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_CZ[] PROGMEM = " const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_IT[] PROGMEM = "Calibrazione XYZ compromessa. Punto anteriore sinistro non raggiungibile."; const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_ES[] PROGMEM = "Calibrazion XYZ comprometida. Punto delantero izquierdo no alcanzable."; const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_PL[] PROGMEM = "Kalibracja XYZ niedokladna. Lewy przedni punkt zbyt wysuniety do przodu."; -const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_DE[] PROGMEM = "XYZ-Kalibrierung ungenau. Linker vorderer Kalibrierpunkt ist zu weit nach vorne."; +const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_DE[] PROGMEM = "XYZ-Kalibrierung ungenau. Linker vorderer Kalibrierpunkt ist zu weit vorne."; const char * const MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_EN, MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_CZ, @@ -431,7 +452,7 @@ const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_CZ[] PROGMEM = const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_IT[] PROGMEM = "Calibrazione XYZ compromessa. Punto anteriore destro non raggiungibile."; const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_ES[] PROGMEM = "Calibrazion XYZ comprometida. Punto delantero derecho no alcanzable."; const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_PL[] PROGMEM = "Kalibracja XYZ niedokladna. Prawy przedni punkt zbyt wysuniety do przodu."; -const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_DE[] PROGMEM = "XYZ-Kalibrierung ungenau. Rechter vorderer Kalibrierpunkt ist zu weit nach vorne."; +const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_DE[] PROGMEM = "XYZ-Kalibrierung ungenau. Rechter vorderer Kalibrierpunkt ist zu weit vorne."; const char * const MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_EN, MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_CZ, @@ -494,6 +515,36 @@ const char * const MSG_CALIBRATE_E_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_CALIBRATE_E_DE }; +const char MSG_CALIBRATE_PINDA_EN[] PROGMEM = "Calibrate"; +const char MSG_CALIBRATE_PINDA_CZ[] PROGMEM = "Zkalibrovat"; +const char MSG_CALIBRATE_PINDA_IT[] PROGMEM = "Calibrare"; +const char MSG_CALIBRATE_PINDA_ES[] PROGMEM = "Calibrar"; +const char MSG_CALIBRATE_PINDA_PL[] PROGMEM = "Skalibrowac"; +const char MSG_CALIBRATE_PINDA_DE[] PROGMEM = "Kalibrieren"; +const char * const MSG_CALIBRATE_PINDA_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_CALIBRATE_PINDA_EN, + MSG_CALIBRATE_PINDA_CZ, + MSG_CALIBRATE_PINDA_IT, + MSG_CALIBRATE_PINDA_ES, + MSG_CALIBRATE_PINDA_PL, + MSG_CALIBRATE_PINDA_DE +}; + +const char MSG_CALIBRATION_PINDA_MENU_EN[] PROGMEM = "Temp. calibration"; +const char MSG_CALIBRATION_PINDA_MENU_CZ[] PROGMEM = "Teplot. kalibrace"; +const char MSG_CALIBRATION_PINDA_MENU_IT[] PROGMEM = "Taratura temp."; +const char MSG_CALIBRATION_PINDA_MENU_ES[] PROGMEM = "Calibracion temp."; +const char MSG_CALIBRATION_PINDA_MENU_PL[] PROGMEM = "Cieplna kalibr."; +const char MSG_CALIBRATION_PINDA_MENU_DE[] PROGMEM = "Temp. kalibrieren"; +const char * const MSG_CALIBRATION_PINDA_MENU_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_CALIBRATION_PINDA_MENU_EN, + MSG_CALIBRATION_PINDA_MENU_CZ, + MSG_CALIBRATION_PINDA_MENU_IT, + MSG_CALIBRATION_PINDA_MENU_ES, + MSG_CALIBRATION_PINDA_MENU_PL, + MSG_CALIBRATION_PINDA_MENU_DE +}; + const char MSG_CARD_MENU_EN[] PROGMEM = "Print from SD"; const char MSG_CARD_MENU_CZ[] PROGMEM = "Tisk z SD"; const char MSG_CARD_MENU_IT[] PROGMEM = "Stampa da SD"; @@ -544,7 +595,7 @@ const char MSG_CHANGING_FILAMENT_CZ[] PROGMEM = "Vymena filamentu!"; const char MSG_CHANGING_FILAMENT_IT[] PROGMEM = "Cambiando filam."; const char MSG_CHANGING_FILAMENT_ES[] PROGMEM = "Cambiando filamento"; const char MSG_CHANGING_FILAMENT_PL[] PROGMEM = "Wymiana filamentu"; -const char MSG_CHANGING_FILAMENT_DE[] PROGMEM = "Wechsel filament!"; +const char MSG_CHANGING_FILAMENT_DE[] PROGMEM = "Filament-Wechsel!"; const char * const MSG_CHANGING_FILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_CHANGING_FILAMENT_EN, MSG_CHANGING_FILAMENT_CZ, @@ -554,6 +605,21 @@ const char * const MSG_CHANGING_FILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_CHANGING_FILAMENT_DE }; +const char MSG_CHOOSE_EXTRUDER_EN[] PROGMEM = "Choose extruder:"; +const char MSG_CHOOSE_EXTRUDER_CZ[] PROGMEM = "Vyberte extruder:"; +const char MSG_CHOOSE_EXTRUDER_IT[] PROGMEM = "Seleziona estrusore:"; +const char MSG_CHOOSE_EXTRUDER_ES[] PROGMEM = "Elegir extrusor:"; +const char MSG_CHOOSE_EXTRUDER_PL[] PROGMEM = "Wybierz ekstruder"; +const char MSG_CHOOSE_EXTRUDER_DE[] PROGMEM = "Waehlen Sie Extruder"; +const char * const MSG_CHOOSE_EXTRUDER_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_CHOOSE_EXTRUDER_EN, + MSG_CHOOSE_EXTRUDER_CZ, + MSG_CHOOSE_EXTRUDER_IT, + MSG_CHOOSE_EXTRUDER_ES, + MSG_CHOOSE_EXTRUDER_PL, + MSG_CHOOSE_EXTRUDER_DE +}; + const char MSG_CLEAN_NOZZLE_E_EN[] PROGMEM = "E calibration finished. Please clean the nozzle. Click when done."; const char MSG_CLEAN_NOZZLE_E_CZ[] PROGMEM = "E kalibrace ukoncena. Prosim ocistete trysku. Po te potvrdte tlacitkem."; const char MSG_CLEAN_NOZZLE_E_IT[] PROGMEM = "Calibrazione E terminata. Si prega di pulire l'ugello. Click per continuare."; @@ -584,7 +650,7 @@ const char MSG_CONFIRM_CARRIAGE_AT_THE_TOP_CZ[] PROGMEM = "Dojely oba Z voziky k const char MSG_CONFIRM_CARRIAGE_AT_THE_TOP_IT[] PROGMEM = "I carrelli Z sin/des sono altezza max?"; const char MSG_CONFIRM_CARRIAGE_AT_THE_TOP_ES[] PROGMEM = "Carros Z izq./der. estan arriba maximo?"; const char MSG_CONFIRM_CARRIAGE_AT_THE_TOP_PL[] PROGMEM = "Oba wozki dojechaly do gornej ramy?"; -const char MSG_CONFIRM_CARRIAGE_AT_THE_TOP_DE[] PROGMEM = "Sind Z-Schlitten ganz oben?"; +const char MSG_CONFIRM_CARRIAGE_AT_THE_TOP_DE[] PROGMEM = "Ist der Schlitten ganz oben?"; const char * const MSG_CONFIRM_CARRIAGE_AT_THE_TOP_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_CONFIRM_CARRIAGE_AT_THE_TOP_EN, MSG_CONFIRM_CARRIAGE_AT_THE_TOP_CZ, @@ -599,7 +665,7 @@ const char MSG_CONFIRM_NOZZLE_CLEAN_CZ[] PROGMEM = "Pro uspesnou kalibraci ocist const char MSG_CONFIRM_NOZZLE_CLEAN_IT[] PROGMEM = "Pulire l'ugello per la calibrazione, poi fare click."; const char MSG_CONFIRM_NOZZLE_CLEAN_ES[] PROGMEM = "Limpiar boquilla para calibracion. Click cuando acabes."; const char MSG_CONFIRM_NOZZLE_CLEAN_PL[] PROGMEM = "Dla prawidl. kalibracji prosze oczyscic dysze. Potw. guzikiem."; -const char MSG_CONFIRM_NOZZLE_CLEAN_DE[] PROGMEM = "Bitte reinigen Sie die D\x81se zur Kalibrierung. Klicken wenn fertig."; +const char MSG_CONFIRM_NOZZLE_CLEAN_DE[] PROGMEM = "Bitte entfernen Sie ueberstehendes Filament von der Duese. Klicken wenn sauber."; const char * const MSG_CONFIRM_NOZZLE_CLEAN_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_CONFIRM_NOZZLE_CLEAN_EN, MSG_CONFIRM_NOZZLE_CLEAN_CZ, @@ -614,7 +680,7 @@ const char MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_CZ[] PROGMEM = "Filamenty jsou srovn const char MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_IT[] PROGMEM = "I filamenti sono regolati. Si prega di pulire l'ugello per la calibrazione. Click per continuare."; const char MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_ES[] PROGMEM = "Filamentos ajustados. Limpie la boquilla para calibracion. Haga clic una vez terminado."; const char MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_PL[] PROGMEM = "Dla prawidlowej kalibracji prosze oczyscic dysze. Potem potwierdzic przyciskiem."; -const char MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_DE[] PROGMEM = "Filaments sind jetzt eingestellt. Bitte reinigen Sie die Duese zur Kalibrierung. Klicken wenn fertig."; +const char MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_DE[] PROGMEM = "Filamente sind jetzt eingestellt. Bitte reinigen Sie die Duese zur Kalibrierung. Klicken wenn fertig."; const char * const MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_EN, MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_CZ, @@ -664,12 +730,27 @@ const char * const MSG_COUNT_X_LANG_TABLE[1] PROGMEM = { MSG_COUNT_X_EN }; +const char MSG_CURRENT_EN[] PROGMEM = "Current"; +const char MSG_CURRENT_CZ[] PROGMEM = "Pouze aktualni"; +const char MSG_CURRENT_IT[] PROGMEM = "Attuale"; +const char MSG_CURRENT_ES[] PROGMEM = "Actual"; +const char MSG_CURRENT_PL[] PROGMEM = "Tylko aktualne"; +const char MSG_CURRENT_DE[] PROGMEM = "Aktuelles"; +const char * const MSG_CURRENT_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_CURRENT_EN, + MSG_CURRENT_CZ, + MSG_CURRENT_IT, + MSG_CURRENT_ES, + MSG_CURRENT_PL, + MSG_CURRENT_DE +}; + const char MSG_DISABLE_STEPPERS_EN[] PROGMEM = "Disable steppers"; const char MSG_DISABLE_STEPPERS_CZ[] PROGMEM = "Vypnout motory"; const char MSG_DISABLE_STEPPERS_IT[] PROGMEM = "Disabilit motori"; const char MSG_DISABLE_STEPPERS_ES[] PROGMEM = "Apagar motores"; const char MSG_DISABLE_STEPPERS_PL[] PROGMEM = "Wylaczyc silniki"; -const char MSG_DISABLE_STEPPERS_DE[] PROGMEM = "Deaktiviere Motor"; +const char MSG_DISABLE_STEPPERS_DE[] PROGMEM = "Motoren aus"; const char * const MSG_DISABLE_STEPPERS_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_DISABLE_STEPPERS_EN, MSG_DISABLE_STEPPERS_CZ, @@ -682,7 +763,7 @@ const char * const MSG_DISABLE_STEPPERS_LANG_TABLE[LANG_NUM] PROGMEM = { const char MSG_DWELL_EN[] PROGMEM = "Sleep..."; const char MSG_DWELL_IT[] PROGMEM = "Sospensione..."; const char MSG_DWELL_ES[] PROGMEM = "En espera"; -const char MSG_DWELL_DE[] PROGMEM = "Schlaf..."; +const char MSG_DWELL_DE[] PROGMEM = "Einen Moment bitte."; const char * const MSG_DWELL_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_DWELL_EN, MSG_DWELL_EN, @@ -776,12 +857,77 @@ const char * const MSG_EXTERNAL_RESET_LANG_TABLE[1] PROGMEM = { MSG_EXTERNAL_RESET_EN }; +const char MSG_EXTRUDER_EN[] PROGMEM = "Extruder"; +const char MSG_EXTRUDER_IT[] PROGMEM = "Estrusore"; +const char MSG_EXTRUDER_ES[] PROGMEM = "Extrusor"; +const char MSG_EXTRUDER_PL[] PROGMEM = "Ekstruder"; +const char * const MSG_EXTRUDER_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_EXTRUDER_EN, + MSG_EXTRUDER_EN, + MSG_EXTRUDER_IT, + MSG_EXTRUDER_ES, + MSG_EXTRUDER_PL, + MSG_EXTRUDER_EN +}; + +const char MSG_EXTRUDER_1_EN[] PROGMEM = "Extruder 1"; +const char MSG_EXTRUDER_1_IT[] PROGMEM = "Estrusore 1"; +const char MSG_EXTRUDER_1_ES[] PROGMEM = "Extrusor 1"; +const char MSG_EXTRUDER_1_PL[] PROGMEM = "Ekstruder 1"; +const char * const MSG_EXTRUDER_1_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_EXTRUDER_1_EN, + MSG_EXTRUDER_1_EN, + MSG_EXTRUDER_1_IT, + MSG_EXTRUDER_1_ES, + MSG_EXTRUDER_1_PL, + MSG_EXTRUDER_1_EN +}; + +const char MSG_EXTRUDER_2_EN[] PROGMEM = "Extruder 2"; +const char MSG_EXTRUDER_2_IT[] PROGMEM = "Estrusore 2"; +const char MSG_EXTRUDER_2_ES[] PROGMEM = "Extrusor 2"; +const char MSG_EXTRUDER_2_PL[] PROGMEM = "Ekstruder 2"; +const char * const MSG_EXTRUDER_2_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_EXTRUDER_2_EN, + MSG_EXTRUDER_2_EN, + MSG_EXTRUDER_2_IT, + MSG_EXTRUDER_2_ES, + MSG_EXTRUDER_2_PL, + MSG_EXTRUDER_2_EN +}; + +const char MSG_EXTRUDER_3_EN[] PROGMEM = "Extruder 3"; +const char MSG_EXTRUDER_3_IT[] PROGMEM = "Estrusore 3"; +const char MSG_EXTRUDER_3_ES[] PROGMEM = "Extrusor 3"; +const char MSG_EXTRUDER_3_PL[] PROGMEM = "Ekstruder 3"; +const char * const MSG_EXTRUDER_3_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_EXTRUDER_3_EN, + MSG_EXTRUDER_3_EN, + MSG_EXTRUDER_3_IT, + MSG_EXTRUDER_3_ES, + MSG_EXTRUDER_3_PL, + MSG_EXTRUDER_3_EN +}; + +const char MSG_EXTRUDER_4_EN[] PROGMEM = "Extruder 4"; +const char MSG_EXTRUDER_4_IT[] PROGMEM = "Estrusore 4"; +const char MSG_EXTRUDER_4_ES[] PROGMEM = "Extrusor 4"; +const char MSG_EXTRUDER_4_PL[] PROGMEM = "Ekstruder 4"; +const char * const MSG_EXTRUDER_4_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_EXTRUDER_4_EN, + MSG_EXTRUDER_4_EN, + MSG_EXTRUDER_4_IT, + MSG_EXTRUDER_4_ES, + MSG_EXTRUDER_4_PL, + MSG_EXTRUDER_4_EN +}; + const char MSG_E_CAL_KNOB_EN[] PROGMEM = "Rotate knob until mark reaches extruder body. Click when done."; const char MSG_E_CAL_KNOB_CZ[] PROGMEM = "Otacejte tlacitkem dokud znacka nedosahne tela extruderu. Potvrdte tlacitkem."; const char MSG_E_CAL_KNOB_IT[] PROGMEM = "Girare la manopola affinche' il segno raggiunga il corpo dell'estrusore. Click per continuare."; const char MSG_E_CAL_KNOB_ES[] PROGMEM = "Rotar el mando hasta que la marca llegue al cuerpo del extrusor. Haga clic una vez terminado."; const char MSG_E_CAL_KNOB_PL[] PROGMEM = "Prosze otaczac przycisk poki znacznik nie dosiegnie ciala ekstrudera. Potwierdzic przyciskiem."; -const char MSG_E_CAL_KNOB_DE[] PROGMEM = "Dreh den Knopf bis das Extruder Zeichen erreicht ist. Klicken wenn fertig."; +const char MSG_E_CAL_KNOB_DE[] PROGMEM = "Knopf drehen bis die Filamentmarkierung erreicht ist. Klicken wenn fertig."; const char * const MSG_E_CAL_KNOB_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_E_CAL_KNOB_EN, MSG_E_CAL_KNOB_CZ, @@ -806,7 +952,7 @@ const char MSG_FAN_SPEED_CZ[] PROGMEM = "Rychlost vent."; const char MSG_FAN_SPEED_IT[] PROGMEM = "Velocita vent."; const char MSG_FAN_SPEED_ES[] PROGMEM = "Velocidad Vent."; const char MSG_FAN_SPEED_PL[] PROGMEM = "Predkosc went."; -const char MSG_FAN_SPEED_DE[] PROGMEM = "Lueftergeschw."; +const char MSG_FAN_SPEED_DE[] PROGMEM = "Luefter-Tempo"; const char * const MSG_FAN_SPEED_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_FAN_SPEED_EN, MSG_FAN_SPEED_CZ, @@ -826,7 +972,7 @@ const char MSG_FILAMENTCHANGE_CZ[] PROGMEM = "Vymenit filament"; const char MSG_FILAMENTCHANGE_IT[] PROGMEM = "Camb. filamento"; const char MSG_FILAMENTCHANGE_ES[] PROGMEM = "Cambiar filamento"; const char MSG_FILAMENTCHANGE_PL[] PROGMEM = "Wymienic filament"; -const char MSG_FILAMENTCHANGE_DE[] PROGMEM = "Wechsel filament"; +const char MSG_FILAMENTCHANGE_DE[] PROGMEM = "Filament-Wechsel"; const char * const MSG_FILAMENTCHANGE_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_FILAMENTCHANGE_EN, MSG_FILAMENTCHANGE_CZ, @@ -841,7 +987,7 @@ const char MSG_FILAMENT_CLEAN_CZ[] PROGMEM = "Je barva cista?"; const char MSG_FILAMENT_CLEAN_IT[] PROGMEM = "Il colore e' nitido?"; const char MSG_FILAMENT_CLEAN_ES[] PROGMEM = "Es el nuevo color nitido?"; const char MSG_FILAMENT_CLEAN_PL[] PROGMEM = "Czy kolor jest czysty?"; -const char MSG_FILAMENT_CLEAN_DE[] PROGMEM = "Ist Farbe klar?"; +const char MSG_FILAMENT_CLEAN_DE[] PROGMEM = "Ist Farbe rein?"; const char * const MSG_FILAMENT_CLEAN_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_FILAMENT_CLEAN_EN, MSG_FILAMENT_CLEAN_CZ, @@ -852,7 +998,7 @@ const char * const MSG_FILAMENT_CLEAN_LANG_TABLE[LANG_NUM] PROGMEM = { }; const char MSG_FILAMENT_LOADING_T0_EN[] PROGMEM = "Insert filament into extruder 1. Click when done."; -const char MSG_FILAMENT_LOADING_T0_CZ[] PROGMEM = "Vlo\x9Ete filament do extruderu 1. Potvrdte tlacitkem."; +const char MSG_FILAMENT_LOADING_T0_CZ[] PROGMEM = "Vlozte filament do extruderu 1. Potvrdte tlacitkem."; const char MSG_FILAMENT_LOADING_T0_IT[] PROGMEM = "Inserire filamento nell'estrusore 1. Click per continuare."; const char MSG_FILAMENT_LOADING_T0_ES[] PROGMEM = "Insertar filamento en el extrusor 1. Haga clic una vez terminado."; const char MSG_FILAMENT_LOADING_T0_PL[] PROGMEM = "Wloz filament do ekstrudera 1. Potwierdz przyciskiem."; @@ -867,7 +1013,7 @@ const char * const MSG_FILAMENT_LOADING_T0_LANG_TABLE[LANG_NUM] PROGMEM = { }; const char MSG_FILAMENT_LOADING_T1_EN[] PROGMEM = "Insert filament into extruder 2. Click when done."; -const char MSG_FILAMENT_LOADING_T1_CZ[] PROGMEM = "Vlo\x9Ete filament do extruderu 2. Potvrdte tlacitkem."; +const char MSG_FILAMENT_LOADING_T1_CZ[] PROGMEM = "Vlozte filament do extruderu 2. Potvrdte tlacitkem."; const char MSG_FILAMENT_LOADING_T1_IT[] PROGMEM = "Inserire filamento nell'estrusore 2. Click per continuare."; const char MSG_FILAMENT_LOADING_T1_ES[] PROGMEM = "Insertar filamento en el extrusor 2. Haga clic una vez terminado."; const char MSG_FILAMENT_LOADING_T1_PL[] PROGMEM = "Wloz filament do ekstrudera 2. Potwierdz przyciskiem."; @@ -882,7 +1028,7 @@ const char * const MSG_FILAMENT_LOADING_T1_LANG_TABLE[LANG_NUM] PROGMEM = { }; const char MSG_FILAMENT_LOADING_T2_EN[] PROGMEM = "Insert filament into extruder 3. Click when done."; -const char MSG_FILAMENT_LOADING_T2_CZ[] PROGMEM = "Vlo\x9Ete filament do extruderu 3. Potvrdte tlacitkem."; +const char MSG_FILAMENT_LOADING_T2_CZ[] PROGMEM = "Vlozte filament do extruderu 3. Potvrdte tlacitkem."; const char MSG_FILAMENT_LOADING_T2_IT[] PROGMEM = "Inserire filamento nell'estrusore 3. Click per continuare."; const char MSG_FILAMENT_LOADING_T2_ES[] PROGMEM = "Insertar filamento en el extrusor 3. Haga clic una vez terminado."; const char MSG_FILAMENT_LOADING_T2_PL[] PROGMEM = "Wloz filament do ekstrudera 3. Potwierdz przyciskiem."; @@ -897,7 +1043,7 @@ const char * const MSG_FILAMENT_LOADING_T2_LANG_TABLE[LANG_NUM] PROGMEM = { }; const char MSG_FILAMENT_LOADING_T3_EN[] PROGMEM = "Insert filament into extruder 4. Click when done."; -const char MSG_FILAMENT_LOADING_T3_CZ[] PROGMEM = "Vlo\x9Ete filament do extruderu 4. Potvrdte tlacitkem."; +const char MSG_FILAMENT_LOADING_T3_CZ[] PROGMEM = "Vlozte filament do extruderu 4. Potvrdte tlacitkem."; const char MSG_FILAMENT_LOADING_T3_IT[] PROGMEM = "Inserire filamento nell'estrusore 4. Click per continuare."; const char MSG_FILAMENT_LOADING_T3_ES[] PROGMEM = "Insertar filamento en el extrusor 4. Haga clic una vez terminado."; const char MSG_FILAMENT_LOADING_T3_PL[] PROGMEM = "Wloz filament do ekstrudera 4. Potwierdz przyciskiem."; @@ -926,7 +1072,7 @@ const char MSG_FIL_ADJUSTING_CZ[] PROGMEM = "Probiha srovnani filamentu. Prosim const char MSG_FIL_ADJUSTING_IT[] PROGMEM = "Filamento in fase di regolazione. Attendere prego."; const char MSG_FIL_ADJUSTING_ES[] PROGMEM = "Ajustando filamentos. Esperar por favor."; const char MSG_FIL_ADJUSTING_PL[] PROGMEM = "Przebiega wyrownanie filamentow. Prosze czekac."; -const char MSG_FIL_ADJUSTING_DE[] PROGMEM = "Einstellen Filament. Bitte warten."; +const char MSG_FIL_ADJUSTING_DE[] PROGMEM = "Filament positionieren. Bitte warten."; const char * const MSG_FIL_ADJUSTING_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_FIL_ADJUSTING_EN, MSG_FIL_ADJUSTING_CZ, @@ -936,34 +1082,18 @@ const char * const MSG_FIL_ADJUSTING_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_FIL_ADJUSTING_DE }; -const char MSG_FIL_LOADED_CHECK_EN[] PROGMEM = "Is filament loaded?"; -const char MSG_FIL_LOADED_CHECK_CZ[] PROGMEM = "Je filament zaveden?"; -const char MSG_FIL_LOADED_CHECK_IT[] PROGMEM = "Filamento caricato?"; -const char MSG_FIL_LOADED_CHECK_ES[] PROGMEM = "Esta cargado el filamento?"; -const char MSG_FIL_LOADED_CHECK_PL[] PROGMEM = "Czy filament jest wprowadzony?"; -const char MSG_FIL_LOADED_CHECK_DE[] PROGMEM = "Filament eingelegt?"; -const char * const MSG_FIL_LOADED_CHECK_LANG_TABLE[LANG_NUM] PROGMEM = { - MSG_FIL_LOADED_CHECK_EN, - MSG_FIL_LOADED_CHECK_CZ, - MSG_FIL_LOADED_CHECK_IT, - MSG_FIL_LOADED_CHECK_ES, - MSG_FIL_LOADED_CHECK_PL, - MSG_FIL_LOADED_CHECK_DE -}; - -const char MSG_FIL_TUNING_EN[] PROGMEM = "Rotate the knob to adjust filament."; -const char MSG_FIL_TUNING_CZ[] PROGMEM = "Otacenim tlacitka doladte pozici filamentu."; -const char MSG_FIL_TUNING_IT[] PROGMEM = "Girare la manopola per regolare il filamento"; -const char MSG_FIL_TUNING_ES[] PROGMEM = "Rotar el mando para ajustar el filamento."; -const char MSG_FIL_TUNING_PL[] PROGMEM = "Obrotem przycisku dostroj pozycje filamentu."; -const char MSG_FIL_TUNING_DE[] PROGMEM = "Knopf drehen um Filam. einzustellen."; -const char * const MSG_FIL_TUNING_LANG_TABLE[LANG_NUM] PROGMEM = { - MSG_FIL_TUNING_EN, - MSG_FIL_TUNING_CZ, - MSG_FIL_TUNING_IT, - MSG_FIL_TUNING_ES, - MSG_FIL_TUNING_PL, - MSG_FIL_TUNING_DE +const char MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION_EN[] PROGMEM = "Iteration "; +const char MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION_CZ[] PROGMEM = "Iterace "; +const char MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION_IT[] PROGMEM = "Reiterazione "; +const char MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION_ES[] PROGMEM = "Reiteracion "; +const char MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION_PL[] PROGMEM = "Iteracja "; +const char * const MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION_EN, + MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION_CZ, + MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION_IT, + MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION_ES, + MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION_PL, + MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION_EN }; const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_EN[] PROGMEM = "Searching bed calibration point"; @@ -996,6 +1126,21 @@ const char * const MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_LANG_TABLE[LANG_NUM] PROGM MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_DE }; +const char MSG_FINISHING_MOVEMENTS_EN[] PROGMEM = "Finishing movements"; +const char MSG_FINISHING_MOVEMENTS_CZ[] PROGMEM = "Dokoncovani pohybu"; +const char MSG_FINISHING_MOVEMENTS_IT[] PROGMEM = "Arresto in corso"; +const char MSG_FINISHING_MOVEMENTS_ES[] PROGMEM = "Term. movimientos"; +const char MSG_FINISHING_MOVEMENTS_PL[] PROGMEM = "Konczenie druku"; +const char MSG_FINISHING_MOVEMENTS_DE[] PROGMEM = "Bewegung beenden"; +const char * const MSG_FINISHING_MOVEMENTS_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_FINISHING_MOVEMENTS_EN, + MSG_FINISHING_MOVEMENTS_CZ, + MSG_FINISHING_MOVEMENTS_IT, + MSG_FINISHING_MOVEMENTS_ES, + MSG_FINISHING_MOVEMENTS_PL, + MSG_FINISHING_MOVEMENTS_DE +}; + const char MSG_FLOW_EN[] PROGMEM = "Flow"; const char MSG_FLOW_CZ[] PROGMEM = "Prutok"; const char MSG_FLOW_IT[] PROGMEM = "Flusso"; @@ -1051,7 +1196,7 @@ const char MSG_HEATING_CZ[] PROGMEM = "Zahrivani"; const char MSG_HEATING_IT[] PROGMEM = "Riscaldamento..."; const char MSG_HEATING_ES[] PROGMEM = "Calentando..."; const char MSG_HEATING_PL[] PROGMEM = "Grzanie..."; -const char MSG_HEATING_DE[] PROGMEM = "Erwaermen"; +const char MSG_HEATING_DE[] PROGMEM = "Aufwaermen"; const char * const MSG_HEATING_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_HEATING_EN, MSG_HEATING_CZ, @@ -1066,7 +1211,7 @@ const char MSG_HEATING_COMPLETE_CZ[] PROGMEM = "Zahrivani OK."; const char MSG_HEATING_COMPLETE_IT[] PROGMEM = "Riscald. completo"; const char MSG_HEATING_COMPLETE_ES[] PROGMEM = "Calentamiento final."; const char MSG_HEATING_COMPLETE_PL[] PROGMEM = "Grzanie OK."; -const char MSG_HEATING_COMPLETE_DE[] PROGMEM = "Erwaermen OK"; +const char MSG_HEATING_COMPLETE_DE[] PROGMEM = "Aufwaermen OK"; const char * const MSG_HEATING_COMPLETE_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_HEATING_COMPLETE_EN, MSG_HEATING_COMPLETE_CZ, @@ -1184,13 +1329,14 @@ const char * const MSG_INVALID_EXTRUDER_LANG_TABLE[1] PROGMEM = { const char MSG_KILLED_EN[] PROGMEM = "KILLED. "; const char MSG_KILLED_IT[] PROGMEM = "IN TILT."; const char MSG_KILLED_ES[] PROGMEM = "PARADA DE EMERGENCIA"; +const char MSG_KILLED_DE[] PROGMEM = "ABGEBROCHEN. "; const char * const MSG_KILLED_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_KILLED_EN, MSG_KILLED_EN, MSG_KILLED_IT, MSG_KILLED_ES, MSG_KILLED_EN, - MSG_KILLED_EN + MSG_KILLED_DE }; const char MSG_LANGUAGE_NAME_EN[] PROGMEM = "English"; @@ -1243,7 +1389,7 @@ const char MSG_LOADING_FILAMENT_CZ[] PROGMEM = "Zavadeni filamentu"; const char MSG_LOADING_FILAMENT_IT[] PROGMEM = "Caricando filam."; const char MSG_LOADING_FILAMENT_ES[] PROGMEM = "Introduciendo filam."; const char MSG_LOADING_FILAMENT_PL[] PROGMEM = "Wprow. filamentu"; -const char MSG_LOADING_FILAMENT_DE[] PROGMEM = "Filament-Eifuehrung"; +const char MSG_LOADING_FILAMENT_DE[] PROGMEM = "Filament leadt"; const char * const MSG_LOADING_FILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_LOADING_FILAMENT_EN, MSG_LOADING_FILAMENT_CZ, @@ -1253,6 +1399,21 @@ const char * const MSG_LOADING_FILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_LOADING_FILAMENT_DE }; +const char MSG_LOAD_ALL_EN[] PROGMEM = "Load all"; +const char MSG_LOAD_ALL_CZ[] PROGMEM = "Zavest vse"; +const char MSG_LOAD_ALL_IT[] PROGMEM = "Caricare tutti"; +const char MSG_LOAD_ALL_ES[] PROGMEM = "Intr. todos fil."; +const char MSG_LOAD_ALL_PL[] PROGMEM = "Zalad. wszystkie"; +const char MSG_LOAD_ALL_DE[] PROGMEM = "Alle laden"; +const char * const MSG_LOAD_ALL_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_LOAD_ALL_EN, + MSG_LOAD_ALL_CZ, + MSG_LOAD_ALL_IT, + MSG_LOAD_ALL_ES, + MSG_LOAD_ALL_PL, + MSG_LOAD_ALL_DE +}; + const char MSG_LOAD_EPROM_EN[] PROGMEM = "Load memory"; const char * const MSG_LOAD_EPROM_LANG_TABLE[1] PROGMEM = { MSG_LOAD_EPROM_EN @@ -1263,7 +1424,7 @@ const char MSG_LOAD_FILAMENT_CZ[] PROGMEM = "Zavest filament"; const char MSG_LOAD_FILAMENT_IT[] PROGMEM = "Carica filamento"; const char MSG_LOAD_FILAMENT_ES[] PROGMEM = "Introducir filam."; const char MSG_LOAD_FILAMENT_PL[] PROGMEM = "Wprowadz filament"; -const char MSG_LOAD_FILAMENT_DE[] PROGMEM = "Lege Filament ein"; +const char MSG_LOAD_FILAMENT_DE[] PROGMEM = "Filament laden"; const char * const MSG_LOAD_FILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_LOAD_FILAMENT_EN, MSG_LOAD_FILAMENT_CZ, @@ -1273,12 +1434,72 @@ const char * const MSG_LOAD_FILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_LOAD_FILAMENT_DE }; +const char MSG_LOAD_FILAMENT_1_EN[] PROGMEM = "Load filament 1"; +const char MSG_LOAD_FILAMENT_1_CZ[] PROGMEM = "Zavest filament 1"; +const char MSG_LOAD_FILAMENT_1_IT[] PROGMEM = "Caricare fil. 1"; +const char MSG_LOAD_FILAMENT_1_ES[] PROGMEM = "Introducir fil. 1"; +const char MSG_LOAD_FILAMENT_1_PL[] PROGMEM = "Zaladowac fil. 1"; +const char MSG_LOAD_FILAMENT_1_DE[] PROGMEM = "Filament 1 laden"; +const char * const MSG_LOAD_FILAMENT_1_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_LOAD_FILAMENT_1_EN, + MSG_LOAD_FILAMENT_1_CZ, + MSG_LOAD_FILAMENT_1_IT, + MSG_LOAD_FILAMENT_1_ES, + MSG_LOAD_FILAMENT_1_PL, + MSG_LOAD_FILAMENT_1_DE +}; + +const char MSG_LOAD_FILAMENT_2_EN[] PROGMEM = "Load filament 2"; +const char MSG_LOAD_FILAMENT_2_CZ[] PROGMEM = "Zavest filament 2"; +const char MSG_LOAD_FILAMENT_2_IT[] PROGMEM = "Caricare fil. 2"; +const char MSG_LOAD_FILAMENT_2_ES[] PROGMEM = "Introducir fil. 2"; +const char MSG_LOAD_FILAMENT_2_PL[] PROGMEM = "Zaladowac fil. 2"; +const char MSG_LOAD_FILAMENT_2_DE[] PROGMEM = "Filament 2 laden"; +const char * const MSG_LOAD_FILAMENT_2_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_LOAD_FILAMENT_2_EN, + MSG_LOAD_FILAMENT_2_CZ, + MSG_LOAD_FILAMENT_2_IT, + MSG_LOAD_FILAMENT_2_ES, + MSG_LOAD_FILAMENT_2_PL, + MSG_LOAD_FILAMENT_2_DE +}; + +const char MSG_LOAD_FILAMENT_3_EN[] PROGMEM = "Load filament 3"; +const char MSG_LOAD_FILAMENT_3_CZ[] PROGMEM = "Zavest filament 3"; +const char MSG_LOAD_FILAMENT_3_IT[] PROGMEM = "Caricare fil. 3"; +const char MSG_LOAD_FILAMENT_3_ES[] PROGMEM = "Introducir fil. 3"; +const char MSG_LOAD_FILAMENT_3_PL[] PROGMEM = "Zaladowac fil. 3"; +const char MSG_LOAD_FILAMENT_3_DE[] PROGMEM = "Filament 3 laden"; +const char * const MSG_LOAD_FILAMENT_3_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_LOAD_FILAMENT_3_EN, + MSG_LOAD_FILAMENT_3_CZ, + MSG_LOAD_FILAMENT_3_IT, + MSG_LOAD_FILAMENT_3_ES, + MSG_LOAD_FILAMENT_3_PL, + MSG_LOAD_FILAMENT_3_DE +}; + +const char MSG_LOAD_FILAMENT_4_EN[] PROGMEM = "Load filament 4"; +const char MSG_LOAD_FILAMENT_4_CZ[] PROGMEM = "Zavest filament 4"; +const char MSG_LOAD_FILAMENT_4_IT[] PROGMEM = "Caricare fil. 4"; +const char MSG_LOAD_FILAMENT_4_ES[] PROGMEM = "Introducir fil. 4"; +const char MSG_LOAD_FILAMENT_4_PL[] PROGMEM = "Zaladowac fil. 4"; +const char MSG_LOAD_FILAMENT_4_DE[] PROGMEM = "Filament 4 laden"; +const char * const MSG_LOAD_FILAMENT_4_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_LOAD_FILAMENT_4_EN, + MSG_LOAD_FILAMENT_4_CZ, + MSG_LOAD_FILAMENT_4_IT, + MSG_LOAD_FILAMENT_4_ES, + MSG_LOAD_FILAMENT_4_PL, + MSG_LOAD_FILAMENT_4_DE +}; + const char MSG_LOOSE_PULLEY_EN[] PROGMEM = "Loose pulley"; const char MSG_LOOSE_PULLEY_CZ[] PROGMEM = "Uvolnena remenicka"; const char MSG_LOOSE_PULLEY_IT[] PROGMEM = "Puleggia lenta"; const char MSG_LOOSE_PULLEY_ES[] PROGMEM = "Polea suelta"; const char MSG_LOOSE_PULLEY_PL[] PROGMEM = "Kolo pasowe"; -const char MSG_LOOSE_PULLEY_DE[] PROGMEM = "Lose Riemenschei."; +const char MSG_LOOSE_PULLEY_DE[] PROGMEM = "Lose Riemenscheibe"; const char * const MSG_LOOSE_PULLEY_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_LOOSE_PULLEY_EN, MSG_LOOSE_PULLEY_CZ, @@ -1348,7 +1569,7 @@ const char MSG_MARK_FIL_CZ[] PROGMEM = "Oznacte filament 100 mm od tela extruder const char MSG_MARK_FIL_IT[] PROGMEM = "Segnare il filamento a 100 mm di distanza dal corpo dell'estrusore. Click per continuare."; const char MSG_MARK_FIL_ES[] PROGMEM = "Marque el filamento 100 mm por encima del final del extrusor. Hacer clic una vez terminado."; const char MSG_MARK_FIL_PL[] PROGMEM = "Prosze oznaczyc filament 100 mm od ciala ekstrudera. Potwierdzic przyciskiem."; -const char MSG_MARK_FIL_DE[] PROGMEM = "Markier Filament 100mm vom Extrudergehaeuse. Klicken wenn Fertig."; +const char MSG_MARK_FIL_DE[] PROGMEM = "Filament 100mm vom Extrudergehaeuse markieren. Klicken wenn Fertig."; const char * const MSG_MARK_FIL_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_MARK_FIL_EN, MSG_MARK_FIL_CZ, @@ -1449,7 +1670,7 @@ const char MSG_MOVE_AXIS_CZ[] PROGMEM = "Posunout osu"; const char MSG_MOVE_AXIS_IT[] PROGMEM = "Muovi asse"; const char MSG_MOVE_AXIS_ES[] PROGMEM = "Mover ejes"; const char MSG_MOVE_AXIS_PL[] PROGMEM = "Ruch osi"; -const char MSG_MOVE_AXIS_DE[] PROGMEM = "Bewege Achse"; +const char MSG_MOVE_AXIS_DE[] PROGMEM = "Achsbewegung"; const char * const MSG_MOVE_AXIS_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_MOVE_AXIS_EN, MSG_MOVE_AXIS_CZ, @@ -1464,7 +1685,7 @@ const char MSG_MOVE_CARRIAGE_TO_THE_TOP_CZ[] PROGMEM = "Kalibrace XYZ. Otacenim const char MSG_MOVE_CARRIAGE_TO_THE_TOP_IT[] PROGMEM = "Calibrazione XYZ. Ruotare la manopola per alzare il carrello Z fino all'altezza massima. Click per terminare."; const char MSG_MOVE_CARRIAGE_TO_THE_TOP_ES[] PROGMEM = "Calibrando XYZ. Gira el boton para subir el carro Z hasta golpe piezas superioras. Despues haz clic."; const char MSG_MOVE_CARRIAGE_TO_THE_TOP_PL[] PROGMEM = "Kalibracja XYZ. Przekrec galke, aby przesunac os Z do gornych krancowek. Nacisnij, by potwierdzic."; -const char MSG_MOVE_CARRIAGE_TO_THE_TOP_DE[] PROGMEM = "Kalibrieren von XYZ. Drehen Sie den Knopf, um den Z-Schlitten bis zum Anschlag zu bewegen. Klicken wenn fertig."; +const char MSG_MOVE_CARRIAGE_TO_THE_TOP_DE[] PROGMEM = "Kalibrieren von XYZ. Drehen Sie den Knopf bis der obere Anschlag erreicht wird. Klicken wenn ganz oben."; const char * const MSG_MOVE_CARRIAGE_TO_THE_TOP_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_MOVE_CARRIAGE_TO_THE_TOP_EN, MSG_MOVE_CARRIAGE_TO_THE_TOP_CZ, @@ -1479,7 +1700,7 @@ const char MSG_MOVE_CARRIAGE_TO_THE_TOP_Z_CZ[] PROGMEM = "Kalibrace Z. Otacenim const char MSG_MOVE_CARRIAGE_TO_THE_TOP_Z_IT[] PROGMEM = "Calibrazione Z. Ruotare la manopola per alzare il carrello Z fino all'altezza massima. Click per terminare."; const char MSG_MOVE_CARRIAGE_TO_THE_TOP_Z_ES[] PROGMEM = "Calibrando Z. Gira el boton para subir el carro Z hasta golpe piezas superioras. Despues haz clic."; const char MSG_MOVE_CARRIAGE_TO_THE_TOP_Z_PL[] PROGMEM = "Kalibracja Z. Przekrec galke, aby przesunac os Z do gornych krancowek. Nacisnij, by potwierdzic."; -const char MSG_MOVE_CARRIAGE_TO_THE_TOP_Z_DE[] PROGMEM = "Kalibrieren von Z. Drehen Sie den Knopf, um den Z-Schlitten bis zum Anschlag zu bewegen. Klicken wenn fertig."; +const char MSG_MOVE_CARRIAGE_TO_THE_TOP_Z_DE[] PROGMEM = "Kalibrieren von Z. Drehen Sie den Knopf bis der obere Anschlag erreicht wird. Klicken wenn ganz oben."; const char * const MSG_MOVE_CARRIAGE_TO_THE_TOP_Z_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_MOVE_CARRIAGE_TO_THE_TOP_Z_EN, MSG_MOVE_CARRIAGE_TO_THE_TOP_Z_CZ, @@ -1594,7 +1815,7 @@ const char MSG_NOT_COLOR_CZ[] PROGMEM = "Barva neni cista"; const char MSG_NOT_COLOR_IT[] PROGMEM = "Colore non puro"; const char MSG_NOT_COLOR_ES[] PROGMEM = "Color no homogeneo"; const char MSG_NOT_COLOR_PL[] PROGMEM = "Kolor zanieczysz."; -const char MSG_NOT_COLOR_DE[] PROGMEM = "Farbe nicht klar"; +const char MSG_NOT_COLOR_DE[] PROGMEM = "Farbe unklar"; const char * const MSG_NOT_COLOR_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_NOT_COLOR_EN, MSG_NOT_COLOR_CZ, @@ -1609,7 +1830,7 @@ const char MSG_NOT_LOADED_CZ[] PROGMEM = "Filament nezaveden"; const char MSG_NOT_LOADED_IT[] PROGMEM = "Fil. non caricato"; const char MSG_NOT_LOADED_ES[] PROGMEM = "Fil. no introducido"; const char MSG_NOT_LOADED_PL[] PROGMEM = "Brak filamentu"; -const char MSG_NOT_LOADED_DE[] PROGMEM = "Filam. nicht geladen"; +const char MSG_NOT_LOADED_DE[] PROGMEM = "Fil. nicht geladen"; const char * const MSG_NOT_LOADED_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_NOT_LOADED_EN, MSG_NOT_LOADED_CZ, @@ -1692,7 +1913,7 @@ const char MSG_PAPER_CZ[] PROGMEM = "Umistete list papiru na podlozku a udrzujte const char MSG_PAPER_IT[] PROGMEM = "Porre un foglio sotto l'ugello durante la calibrazione dei primi 4 punti. In caso l'ugello muova il foglio spegnere prontamente la stampante."; const char MSG_PAPER_ES[] PROGMEM = "Colocar una hoja de papel sobre la superficie de impresion durante la calibracion de los primeros 4 puntos. Si la boquilla mueve el papel, apagar impresora inmediatamente."; const char MSG_PAPER_PL[] PROGMEM = "Umiesc kartke papieru na podkladce i trzymaj pod dysza podczas pomiaru pierwszych 4 punktow. Jesli dysza zahaczy o papier, wylacz drukarke."; -const char MSG_PAPER_DE[] PROGMEM = "Legen ein Blatt Papier unter die Duese waehrend der Kalibrierung der ersten 4 Punkte. Wenn die Duese das Papier einfaengt, Drucker sofort ausschalten"; +const char MSG_PAPER_DE[] PROGMEM = "Legen ein Blatt Papier unter die Duese waehrend der Kalibrierung der ersten 4 Punkte. Wenn die Duese das Papier einklemmt, Drucker sofort ausschalten"; const char * const MSG_PAPER_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_PAPER_EN, MSG_PAPER_CZ, @@ -1707,7 +1928,7 @@ const char MSG_PAUSE_PRINT_CZ[] PROGMEM = "Pozastavit tisk"; const char MSG_PAUSE_PRINT_IT[] PROGMEM = "Metti in pausa"; const char MSG_PAUSE_PRINT_ES[] PROGMEM = "Pausar impresion"; const char MSG_PAUSE_PRINT_PL[] PROGMEM = "Przerwac druk"; -const char MSG_PAUSE_PRINT_DE[] PROGMEM = "Druck aussetzen"; +const char MSG_PAUSE_PRINT_DE[] PROGMEM = "Druck unterbrech."; const char * const MSG_PAUSE_PRINT_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_PAUSE_PRINT_EN, MSG_PAUSE_PRINT_CZ, @@ -1731,6 +1952,81 @@ const char * const MSG_PICK_Z_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_PICK_Z_DE }; +const char MSG_PID_EXTRUDER_EN[] PROGMEM = "PID calibration"; +const char MSG_PID_EXTRUDER_CZ[] PROGMEM = "PID kalibrace"; +const char MSG_PID_EXTRUDER_IT[] PROGMEM = "Calibrazione PID"; +const char MSG_PID_EXTRUDER_ES[] PROGMEM = "Calibracion PID"; +const char MSG_PID_EXTRUDER_PL[] PROGMEM = "Kalibracja PID"; +const char MSG_PID_EXTRUDER_DE[] PROGMEM = "PID Kalibrierung"; +const char * const MSG_PID_EXTRUDER_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_PID_EXTRUDER_EN, + MSG_PID_EXTRUDER_CZ, + MSG_PID_EXTRUDER_IT, + MSG_PID_EXTRUDER_ES, + MSG_PID_EXTRUDER_PL, + MSG_PID_EXTRUDER_DE +}; + +const char MSG_PID_FINISHED_EN[] PROGMEM = "PID cal. finished"; +const char MSG_PID_FINISHED_CZ[] PROGMEM = "PID kal. ukoncena"; +const char MSG_PID_FINISHED_IT[] PROGMEM = "Cal. PID completa"; +const char MSG_PID_FINISHED_ES[] PROGMEM = "Cal. PID terminada"; +const char MSG_PID_FINISHED_PL[] PROGMEM = "Kal. PID zakonczona"; +const char MSG_PID_FINISHED_DE[] PROGMEM = "PID Kalib. fertig"; +const char * const MSG_PID_FINISHED_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_PID_FINISHED_EN, + MSG_PID_FINISHED_CZ, + MSG_PID_FINISHED_IT, + MSG_PID_FINISHED_ES, + MSG_PID_FINISHED_PL, + MSG_PID_FINISHED_DE +}; + +const char MSG_PID_RUNNING_EN[] PROGMEM = "PID cal. "; +const char MSG_PID_RUNNING_CZ[] PROGMEM = "PID kal. "; +const char MSG_PID_RUNNING_IT[] PROGMEM = "Cal. PID"; +const char MSG_PID_RUNNING_ES[] PROGMEM = "Cal. PID "; +const char MSG_PID_RUNNING_PL[] PROGMEM = "Kal. PID"; +const char MSG_PID_RUNNING_DE[] PROGMEM = "PID Kalib."; +const char * const MSG_PID_RUNNING_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_PID_RUNNING_EN, + MSG_PID_RUNNING_CZ, + MSG_PID_RUNNING_IT, + MSG_PID_RUNNING_ES, + MSG_PID_RUNNING_PL, + MSG_PID_RUNNING_DE +}; + +const char MSG_PINDA_NOT_CALIBRATED_EN[] PROGMEM = "Temperature calibration has not been run yet"; +const char MSG_PINDA_NOT_CALIBRATED_CZ[] PROGMEM = "Tiskarna nebyla teplotne zkalibrovana"; +const char MSG_PINDA_NOT_CALIBRATED_IT[] PROGMEM = "Taratura della temperatura non ancora eseguita"; +const char MSG_PINDA_NOT_CALIBRATED_ES[] PROGMEM = "La temperatura de calibracion no ha sido ajustada"; +const char MSG_PINDA_NOT_CALIBRATED_PL[] PROGMEM = "Cieplna kalibracja nie byla przeprowadzona"; +const char MSG_PINDA_NOT_CALIBRATED_DE[] PROGMEM = "Temperatur wurde nicht kalibriert"; +const char * const MSG_PINDA_NOT_CALIBRATED_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_PINDA_NOT_CALIBRATED_EN, + MSG_PINDA_NOT_CALIBRATED_CZ, + MSG_PINDA_NOT_CALIBRATED_IT, + MSG_PINDA_NOT_CALIBRATED_ES, + MSG_PINDA_NOT_CALIBRATED_PL, + MSG_PINDA_NOT_CALIBRATED_DE +}; + +const char MSG_PINDA_PREHEAT_EN[] PROGMEM = "PINDA Heating"; +const char MSG_PINDA_PREHEAT_CZ[] PROGMEM = "Nahrivani PINDA"; +const char MSG_PINDA_PREHEAT_IT[] PROGMEM = "Riscald. PINDA"; +const char MSG_PINDA_PREHEAT_ES[] PROGMEM = "Calentando PINDA"; +const char MSG_PINDA_PREHEAT_PL[] PROGMEM = "Grzanie PINDA"; +const char MSG_PINDA_PREHEAT_DE[] PROGMEM = "PINDA erwaermen"; +const char * const MSG_PINDA_PREHEAT_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_PINDA_PREHEAT_EN, + MSG_PINDA_PREHEAT_CZ, + MSG_PINDA_PREHEAT_IT, + MSG_PINDA_PREHEAT_ES, + MSG_PINDA_PREHEAT_PL, + MSG_PINDA_PREHEAT_DE +}; + const char MSG_PLANNER_BUFFER_BYTES_EN[] PROGMEM = " PlannerBufferBytes: "; const char * const MSG_PLANNER_BUFFER_BYTES_LANG_TABLE[1] PROGMEM = { MSG_PLANNER_BUFFER_BYTES_EN @@ -1781,7 +2077,7 @@ const char MSG_PREHEAT_NOZZLE_CZ[] PROGMEM = "Predehrejte trysku!"; const char MSG_PREHEAT_NOZZLE_IT[] PROGMEM = "Preris. ugello!"; const char MSG_PREHEAT_NOZZLE_ES[] PROGMEM = "Precalentar extrusor"; const char MSG_PREHEAT_NOZZLE_PL[] PROGMEM = "Nagrzej dysze!"; -const char MSG_PREHEAT_NOZZLE_DE[] PROGMEM = "Worwaermen Duese"; +const char MSG_PREHEAT_NOZZLE_DE[] PROGMEM = "Duese Vorwaermen"; const char * const MSG_PREHEAT_NOZZLE_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_PREHEAT_NOZZLE_EN, MSG_PREHEAT_NOZZLE_CZ, @@ -1791,6 +2087,21 @@ const char * const MSG_PREHEAT_NOZZLE_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_PREHEAT_NOZZLE_DE }; +const char MSG_PREPARE_FILAMENT_EN[] PROGMEM = "Prepare new filament"; +const char MSG_PREPARE_FILAMENT_CZ[] PROGMEM = "Pripravte filament"; +const char MSG_PREPARE_FILAMENT_IT[] PROGMEM = "Preparare filamento"; +const char MSG_PREPARE_FILAMENT_ES[] PROGMEM = "Preparar filamento"; +const char MSG_PREPARE_FILAMENT_PL[] PROGMEM = "Przygotuj filament"; +const char MSG_PREPARE_FILAMENT_DE[] PROGMEM = "Filam. bereithalten"; +const char * const MSG_PREPARE_FILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_PREPARE_FILAMENT_EN, + MSG_PREPARE_FILAMENT_CZ, + MSG_PREPARE_FILAMENT_IT, + MSG_PREPARE_FILAMENT_ES, + MSG_PREPARE_FILAMENT_PL, + MSG_PREPARE_FILAMENT_DE +}; + const char MSG_PRESS_EN[] PROGMEM = "and press the knob"; const char MSG_PRESS_CZ[] PROGMEM = "a stisknete tlacitko"; const char MSG_PRESS_IT[] PROGMEM = "e cliccare manopola"; @@ -1826,6 +2137,21 @@ const char * const MSG_PRINT_ABORTED_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_PRINT_ABORTED_DE }; +const char MSG_PRINT_PAUSED_EN[] PROGMEM = "Print paused"; +const char MSG_PRINT_PAUSED_CZ[] PROGMEM = "Tisk pozastaven"; +const char MSG_PRINT_PAUSED_IT[] PROGMEM = "Stampa in pausa"; +const char MSG_PRINT_PAUSED_ES[] PROGMEM = "Impresion en pausa"; +const char MSG_PRINT_PAUSED_PL[] PROGMEM = "Druk zatrzymany"; +const char MSG_PRINT_PAUSED_DE[] PROGMEM = "Druck pausiert"; +const char * const MSG_PRINT_PAUSED_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_PRINT_PAUSED_EN, + MSG_PRINT_PAUSED_CZ, + MSG_PRINT_PAUSED_IT, + MSG_PRINT_PAUSED_ES, + MSG_PRINT_PAUSED_PL, + MSG_PRINT_PAUSED_DE +}; + const char MSG_PRUSA3D_EN[] PROGMEM = "prusa3d.com"; const char MSG_PRUSA3D_CZ[] PROGMEM = "prusa3d.cz"; const char MSG_PRUSA3D_PL[] PROGMEM = "prusa3d.cz"; @@ -1867,7 +2193,7 @@ const char MSG_REBOOT_CZ[] PROGMEM = "Restartujte tiskarnu"; const char MSG_REBOOT_IT[] PROGMEM = "Riavvia stampante"; const char MSG_REBOOT_ES[] PROGMEM = "Reiniciar impresora"; const char MSG_REBOOT_PL[] PROGMEM = "Restart drukarki"; -const char MSG_REBOOT_DE[] PROGMEM = "Reboot den Printer"; +const char MSG_REBOOT_DE[] PROGMEM = "Zum Uebernehmen "; const char * const MSG_REBOOT_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_REBOOT_EN, MSG_REBOOT_CZ, @@ -1932,6 +2258,21 @@ const char * const MSG_RESUMING_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_RESUMING_DE }; +const char MSG_RESUMING_PRINT_EN[] PROGMEM = "Resuming print"; +const char MSG_RESUMING_PRINT_CZ[] PROGMEM = "Obnovovani tisku"; +const char MSG_RESUMING_PRINT_IT[] PROGMEM = "Stampa in ripresa"; +const char MSG_RESUMING_PRINT_ES[] PROGMEM = "Reanudar impresion"; +const char MSG_RESUMING_PRINT_PL[] PROGMEM = "Wznawianie druku"; +const char MSG_RESUMING_PRINT_DE[] PROGMEM = "Druck weitergehen"; +const char * const MSG_RESUMING_PRINT_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_RESUMING_PRINT_EN, + MSG_RESUMING_PRINT_CZ, + MSG_RESUMING_PRINT_IT, + MSG_RESUMING_PRINT_ES, + MSG_RESUMING_PRINT_PL, + MSG_RESUMING_PRINT_DE +}; + const char MSG_SD_CANT_ENTER_SUBDIR_EN[] PROGMEM = "Cannot enter subdir: "; const char * const MSG_SD_CANT_ENTER_SUBDIR_LANG_TABLE[1] PROGMEM = { MSG_SD_CANT_ENTER_SUBDIR_EN @@ -2097,7 +2438,7 @@ const char MSG_SELFTEST_CHECK_ENDSTOPS_CZ[] PROGMEM = "Kontrola endstops"; const char MSG_SELFTEST_CHECK_ENDSTOPS_IT[] PROGMEM = "Verifica finecorsa"; const char MSG_SELFTEST_CHECK_ENDSTOPS_ES[] PROGMEM = "Cont. topes final"; const char MSG_SELFTEST_CHECK_ENDSTOPS_PL[] PROGMEM = "Kontrola endstops"; -const char MSG_SELFTEST_CHECK_ENDSTOPS_DE[] PROGMEM = "Pr\x81fe endstops "; +const char MSG_SELFTEST_CHECK_ENDSTOPS_DE[] PROGMEM = "Pruefe Endschalter "; const char * const MSG_SELFTEST_CHECK_ENDSTOPS_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_SELFTEST_CHECK_ENDSTOPS_EN, MSG_SELFTEST_CHECK_ENDSTOPS_CZ, @@ -2112,7 +2453,7 @@ const char MSG_SELFTEST_CHECK_HOTEND_CZ[] PROGMEM = "Kontrola hotend "; const char MSG_SELFTEST_CHECK_HOTEND_IT[] PROGMEM = "Verifica ugello"; const char MSG_SELFTEST_CHECK_HOTEND_ES[] PROGMEM = "Control hotend "; const char MSG_SELFTEST_CHECK_HOTEND_PL[] PROGMEM = "Kontrola hotend "; -const char MSG_SELFTEST_CHECK_HOTEND_DE[] PROGMEM = "Pr\x81fe hotend "; +const char MSG_SELFTEST_CHECK_HOTEND_DE[] PROGMEM = "Pruefe Hotend"; const char * const MSG_SELFTEST_CHECK_HOTEND_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_SELFTEST_CHECK_HOTEND_EN, MSG_SELFTEST_CHECK_HOTEND_CZ, @@ -2127,7 +2468,7 @@ const char MSG_SELFTEST_CHECK_X_CZ[] PROGMEM = "Kontrola X axis "; const char MSG_SELFTEST_CHECK_X_IT[] PROGMEM = "Verifica asse X"; const char MSG_SELFTEST_CHECK_X_ES[] PROGMEM = "Control del eje X"; const char MSG_SELFTEST_CHECK_X_PL[] PROGMEM = "Kontrola X axis "; -const char MSG_SELFTEST_CHECK_X_DE[] PROGMEM = "Pr\x81fe X Achse "; +const char MSG_SELFTEST_CHECK_X_DE[] PROGMEM = "Pruefe X Achse "; const char * const MSG_SELFTEST_CHECK_X_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_SELFTEST_CHECK_X_EN, MSG_SELFTEST_CHECK_X_CZ, @@ -2142,7 +2483,7 @@ const char MSG_SELFTEST_CHECK_Y_CZ[] PROGMEM = "Kontrola Y axis "; const char MSG_SELFTEST_CHECK_Y_IT[] PROGMEM = "Verifica asse Y"; const char MSG_SELFTEST_CHECK_Y_ES[] PROGMEM = "Control del eje Y"; const char MSG_SELFTEST_CHECK_Y_PL[] PROGMEM = "Kontrola Y axis "; -const char MSG_SELFTEST_CHECK_Y_DE[] PROGMEM = "Pr\x81fe Y Achse "; +const char MSG_SELFTEST_CHECK_Y_DE[] PROGMEM = "Pruefe Y Achse "; const char * const MSG_SELFTEST_CHECK_Y_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_SELFTEST_CHECK_Y_EN, MSG_SELFTEST_CHECK_Y_CZ, @@ -2157,7 +2498,7 @@ const char MSG_SELFTEST_CHECK_Z_CZ[] PROGMEM = "Kontrola Z axis "; const char MSG_SELFTEST_CHECK_Z_IT[] PROGMEM = "Verifica asse Z"; const char MSG_SELFTEST_CHECK_Z_ES[] PROGMEM = "Control del eje Z"; const char MSG_SELFTEST_CHECK_Z_PL[] PROGMEM = "Kontrola Z axis "; -const char MSG_SELFTEST_CHECK_Z_DE[] PROGMEM = "Pr\x81fe Z Achse "; +const char MSG_SELFTEST_CHECK_Z_DE[] PROGMEM = "Pruefe Z Achse "; const char * const MSG_SELFTEST_CHECK_Z_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_SELFTEST_CHECK_Z_EN, MSG_SELFTEST_CHECK_Z_CZ, @@ -2172,7 +2513,7 @@ const char MSG_SELFTEST_COOLING_FAN_CZ[] PROGMEM = "Predni tiskovy vent?";; const char MSG_SELFTEST_COOLING_FAN_IT[] PROGMEM = "Vent di stampa ant.?";; const char MSG_SELFTEST_COOLING_FAN_ES[] PROGMEM = "Vent. al frente?";; const char MSG_SELFTEST_COOLING_FAN_PL[] PROGMEM = "Przodni went. druku?";; -const char MSG_SELFTEST_COOLING_FAN_DE[] PROGMEM = "Vord. Frontluefter?"; +const char MSG_SELFTEST_COOLING_FAN_DE[] PROGMEM = "Vorderer Luefter?"; const char * const MSG_SELFTEST_COOLING_FAN_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_SELFTEST_COOLING_FAN_EN, MSG_SELFTEST_COOLING_FAN_CZ, @@ -2197,19 +2538,20 @@ const char * const MSG_SELFTEST_ENDSTOP_LANG_TABLE[LANG_NUM] PROGMEM = { const char MSG_SELFTEST_ENDSTOPS_EN[] PROGMEM = "Endstops"; const char MSG_SELFTEST_ENDSTOPS_IT[] PROGMEM = "Finecorsa (2)"; const char MSG_SELFTEST_ENDSTOPS_ES[] PROGMEM = "Topes final"; +const char MSG_SELFTEST_ENDSTOPS_DE[] PROGMEM = "Endschalter"; const char * const MSG_SELFTEST_ENDSTOPS_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_SELFTEST_ENDSTOPS_EN, MSG_SELFTEST_ENDSTOPS_EN, MSG_SELFTEST_ENDSTOPS_IT, MSG_SELFTEST_ENDSTOPS_ES, MSG_SELFTEST_ENDSTOPS_EN, - MSG_SELFTEST_ENDSTOPS_EN + MSG_SELFTEST_ENDSTOPS_DE }; const char MSG_SELFTEST_ENDSTOP_NOTHIT_EN[] PROGMEM = "Endstop not hit"; const char MSG_SELFTEST_ENDSTOP_NOTHIT_IT[] PROGMEM = "Finec. fuori por."; const char MSG_SELFTEST_ENDSTOP_NOTHIT_ES[] PROGMEM = "Tope fin. no toc."; -const char MSG_SELFTEST_ENDSTOP_NOTHIT_DE[] PROGMEM = "End nicht getrof."; +const char MSG_SELFTEST_ENDSTOP_NOTHIT_DE[] PROGMEM = "Ende nicht getrof."; const char * const MSG_SELFTEST_ENDSTOP_NOTHIT_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_SELFTEST_ENDSTOP_NOTHIT_EN, MSG_SELFTEST_ENDSTOP_NOTHIT_EN, @@ -2237,7 +2579,7 @@ const char MSG_SELFTEST_EXTRUDER_FAN_CZ[] PROGMEM = "Levy vent na trysce?";; const char MSG_SELFTEST_EXTRUDER_FAN_IT[] PROGMEM = "Vent SX sull'ugello?";; const char MSG_SELFTEST_EXTRUDER_FAN_ES[] PROGMEM = "Vent. en la izg?";; const char MSG_SELFTEST_EXTRUDER_FAN_PL[] PROGMEM = "Lewy went na dysze?";; -const char MSG_SELFTEST_EXTRUDER_FAN_DE[] PROGMEM = "Link. Hotendluefter?"; +const char MSG_SELFTEST_EXTRUDER_FAN_DE[] PROGMEM = "Linker Luefter?"; const char * const MSG_SELFTEST_EXTRUDER_FAN_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_SELFTEST_EXTRUDER_FAN_EN, MSG_SELFTEST_EXTRUDER_FAN_CZ, @@ -2252,7 +2594,7 @@ const char MSG_SELFTEST_FAILED_CZ[] PROGMEM = "Selftest selhal "; const char MSG_SELFTEST_FAILED_IT[] PROGMEM = "Autotest fallito"; const char MSG_SELFTEST_FAILED_ES[] PROGMEM = "Autotest fallado"; const char MSG_SELFTEST_FAILED_PL[] PROGMEM = "Selftest nieudany"; -const char MSG_SELFTEST_FAILED_DE[] PROGMEM = "Selbtest fehlgeschlg"; +const char MSG_SELFTEST_FAILED_DE[] PROGMEM = "Selbsttest misslung."; const char * const MSG_SELFTEST_FAILED_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_SELFTEST_FAILED_EN, MSG_SELFTEST_FAILED_CZ, @@ -2431,12 +2773,27 @@ const char * const MSG_SET_ORIGIN_LANG_TABLE[1] PROGMEM = { MSG_SET_ORIGIN_EN }; +const char MSG_SET_TEMPERATURE_EN[] PROGMEM = "Set temperature:"; +const char MSG_SET_TEMPERATURE_CZ[] PROGMEM = "Nastavte teplotu:"; +const char MSG_SET_TEMPERATURE_IT[] PROGMEM = "Imposta temperatura"; +const char MSG_SET_TEMPERATURE_ES[] PROGMEM = "Establecer temp.:"; +const char MSG_SET_TEMPERATURE_PL[] PROGMEM = "Ustawic temperature"; +const char MSG_SET_TEMPERATURE_DE[] PROGMEM = "Temp. einsetzen"; +const char * const MSG_SET_TEMPERATURE_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_SET_TEMPERATURE_EN, + MSG_SET_TEMPERATURE_CZ, + MSG_SET_TEMPERATURE_IT, + MSG_SET_TEMPERATURE_ES, + MSG_SET_TEMPERATURE_PL, + MSG_SET_TEMPERATURE_DE +}; + const char MSG_SHOW_END_STOPS_EN[] PROGMEM = "Show end stops"; const char MSG_SHOW_END_STOPS_CZ[] PROGMEM = "Stav konc. spin."; const char MSG_SHOW_END_STOPS_IT[] PROGMEM = "Stato finecorsa"; const char MSG_SHOW_END_STOPS_ES[] PROGMEM = "Ensena tope final"; const char MSG_SHOW_END_STOPS_PL[] PROGMEM = "Pokaz krancowki"; -const char MSG_SHOW_END_STOPS_DE[] PROGMEM = "Anzeigen endstops"; +const char MSG_SHOW_END_STOPS_DE[] PROGMEM = "Endschalter Stat."; const char * const MSG_SHOW_END_STOPS_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_SHOW_END_STOPS_EN, MSG_SHOW_END_STOPS_CZ, @@ -2551,7 +2908,7 @@ const char MSG_STATS_TOTALFILAMENT_CZ[] PROGMEM = "Filament celkem :"; const char MSG_STATS_TOTALFILAMENT_IT[] PROGMEM = "Filamento tot:"; const char MSG_STATS_TOTALFILAMENT_ES[] PROGMEM = "Filamento total:"; const char MSG_STATS_TOTALFILAMENT_PL[] PROGMEM = "Filament lacznie :"; -const char MSG_STATS_TOTALFILAMENT_DE[] PROGMEM = "Totales Filament:"; +const char MSG_STATS_TOTALFILAMENT_DE[] PROGMEM = "Gesamtfilament:"; const char * const MSG_STATS_TOTALFILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_STATS_TOTALFILAMENT_EN, MSG_STATS_TOTALFILAMENT_CZ, @@ -2599,7 +2956,7 @@ const char MSG_STOP_PRINT_CZ[] PROGMEM = "Zastavit tisk"; const char MSG_STOP_PRINT_IT[] PROGMEM = "Arresta stampa"; const char MSG_STOP_PRINT_ES[] PROGMEM = "Detener impresion"; const char MSG_STOP_PRINT_PL[] PROGMEM = "Zatrzymac druk"; -const char MSG_STOP_PRINT_DE[] PROGMEM = "Druck halten"; +const char MSG_STOP_PRINT_DE[] PROGMEM = "Druck abbrechen"; const char * const MSG_STOP_PRINT_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_STOP_PRINT_EN, MSG_STOP_PRINT_CZ, @@ -2658,7 +3015,7 @@ const char MSG_TAKE_EFFECT_CZ[] PROGMEM = " pro projeveni zmen"; const char MSG_TAKE_EFFECT_IT[] PROGMEM = " per attualizzare"; const char MSG_TAKE_EFFECT_ES[] PROGMEM = " para aplicar cambios"; const char MSG_TAKE_EFFECT_PL[] PROGMEM = " wprow. zmian"; -const char MSG_TAKE_EFFECT_DE[] PROGMEM = " um wirksam zu sein"; +const char MSG_TAKE_EFFECT_DE[] PROGMEM = "Drucker neu starten"; const char * const MSG_TAKE_EFFECT_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_TAKE_EFFECT_EN, MSG_TAKE_EFFECT_CZ, @@ -2683,26 +3040,88 @@ const char * const MSG_TEMPERATURE_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_TEMPERATURE_DE }; +const char MSG_TEMP_CALIBRATION_EN[] PROGMEM = "Temp. cal. "; +const char MSG_TEMP_CALIBRATION_CZ[] PROGMEM = "Tepl. kal. "; +const char MSG_TEMP_CALIBRATION_IT[] PROGMEM = "Cal. temp. "; +const char MSG_TEMP_CALIBRATION_ES[] PROGMEM = "Cal. temp. "; +const char MSG_TEMP_CALIBRATION_PL[] PROGMEM = "Ciepl. kal. "; +const char MSG_TEMP_CALIBRATION_DE[] PROGMEM = "Temp Kalib. "; +const char * const MSG_TEMP_CALIBRATION_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_TEMP_CALIBRATION_EN, + MSG_TEMP_CALIBRATION_CZ, + MSG_TEMP_CALIBRATION_IT, + MSG_TEMP_CALIBRATION_ES, + MSG_TEMP_CALIBRATION_PL, + MSG_TEMP_CALIBRATION_DE +}; + +const char MSG_TEMP_CALIBRATION_DONE_EN[] PROGMEM = "Temperature calibration is finished. Click to continue."; +const char MSG_TEMP_CALIBRATION_DONE_CZ[] PROGMEM = "Teplotni kalibrace dokoncena. Pokracujte stiskem tlacitka."; +const char MSG_TEMP_CALIBRATION_DONE_IT[] PROGMEM = "Taratura temperatura terminata. Fare click per continuare."; +const char MSG_TEMP_CALIBRATION_DONE_ES[] PROGMEM = "Calibracon temperatura terminada. Presionar para continuar."; +const char MSG_TEMP_CALIBRATION_DONE_PL[] PROGMEM = "Cieplna kalibracja zakonczona. Kontynuuj przyciskiem"; +const char MSG_TEMP_CALIBRATION_DONE_DE[] PROGMEM = "Temp. Kalibrierung fertig. Klicken um weiter zu gehen."; +const char * const MSG_TEMP_CALIBRATION_DONE_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_TEMP_CALIBRATION_DONE_EN, + MSG_TEMP_CALIBRATION_DONE_CZ, + MSG_TEMP_CALIBRATION_DONE_IT, + MSG_TEMP_CALIBRATION_DONE_ES, + MSG_TEMP_CALIBRATION_DONE_PL, + MSG_TEMP_CALIBRATION_DONE_DE +}; + +const char MSG_TEMP_CALIBRATION_OFF_EN[] PROGMEM = "Temp. cal. [OFF]"; +const char MSG_TEMP_CALIBRATION_OFF_CZ[] PROGMEM = "Tepl. kal. [OFF]"; +const char MSG_TEMP_CALIBRATION_OFF_IT[] PROGMEM = "Cal. temp. [OFF]"; +const char MSG_TEMP_CALIBRATION_OFF_ES[] PROGMEM = "Cal. temp. [OFF]"; +const char MSG_TEMP_CALIBRATION_OFF_PL[] PROGMEM = "Ciepl. kal. [OFF]"; +const char MSG_TEMP_CALIBRATION_OFF_DE[] PROGMEM = "Temp. Kal. [OFF]"; +const char * const MSG_TEMP_CALIBRATION_OFF_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_TEMP_CALIBRATION_OFF_EN, + MSG_TEMP_CALIBRATION_OFF_CZ, + MSG_TEMP_CALIBRATION_OFF_IT, + MSG_TEMP_CALIBRATION_OFF_ES, + MSG_TEMP_CALIBRATION_OFF_PL, + MSG_TEMP_CALIBRATION_OFF_DE +}; + +const char MSG_TEMP_CALIBRATION_ON_EN[] PROGMEM = "Temp. cal. [ON]"; +const char MSG_TEMP_CALIBRATION_ON_CZ[] PROGMEM = "Tepl. kal. [ON]"; +const char MSG_TEMP_CALIBRATION_ON_IT[] PROGMEM = "Cal. temp. [ON]"; +const char MSG_TEMP_CALIBRATION_ON_ES[] PROGMEM = "Cal. temp. [ON]"; +const char MSG_TEMP_CALIBRATION_ON_PL[] PROGMEM = "Ciepl. kal. [ON]"; +const char MSG_TEMP_CALIBRATION_ON_DE[] PROGMEM = "Temp. Kal. [ON]"; +const char * const MSG_TEMP_CALIBRATION_ON_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_TEMP_CALIBRATION_ON_EN, + MSG_TEMP_CALIBRATION_ON_CZ, + MSG_TEMP_CALIBRATION_ON_IT, + MSG_TEMP_CALIBRATION_ON_ES, + MSG_TEMP_CALIBRATION_ON_PL, + MSG_TEMP_CALIBRATION_ON_DE +}; + const char MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF_EN[] PROGMEM = "SD card [normal]"; const char MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF_PL[] PROGMEM = "karta SD [normal]"; +const char MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF_DE[] PROGMEM = "SD Karte [normal]"; const char * const MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF_EN, MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF_EN, MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF_EN, MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF_EN, MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF_PL, - MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF_EN + MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF_DE }; const char MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON_EN[] PROGMEM = "SD card [FlshAir]"; const char MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON_PL[] PROGMEM = "karta SD[FlshAir]"; +const char MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON_DE[] PROGMEM = "SD Karte [FlashAir]"; const char * const MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON_EN, MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON_EN, MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON_EN, MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON_EN, MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON_PL, - MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON_EN + MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON_DE }; const char MSG_TUNE_EN[] PROGMEM = "Tune"; @@ -2710,7 +3129,7 @@ const char MSG_TUNE_CZ[] PROGMEM = "Ladit"; const char MSG_TUNE_IT[] PROGMEM = "Regola"; const char MSG_TUNE_ES[] PROGMEM = "Ajustar"; const char MSG_TUNE_PL[] PROGMEM = "Nastroic"; -const char MSG_TUNE_DE[] PROGMEM = "Feineinstellen"; +const char MSG_TUNE_DE[] PROGMEM = "Feineinstellung"; const char * const MSG_TUNE_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_TUNE_EN, MSG_TUNE_CZ, @@ -2730,7 +3149,7 @@ const char MSG_UNLOADING_FILAMENT_CZ[] PROGMEM = "Vysouvam filament"; const char MSG_UNLOADING_FILAMENT_IT[] PROGMEM = "Rilasc. filamento"; const char MSG_UNLOADING_FILAMENT_ES[] PROGMEM = "Soltando filamento"; const char MSG_UNLOADING_FILAMENT_PL[] PROGMEM = "Wysuwam filament"; -const char MSG_UNLOADING_FILAMENT_DE[] PROGMEM = "Filam. auswerfen"; +const char MSG_UNLOADING_FILAMENT_DE[] PROGMEM = "Filament auswerfen"; const char * const MSG_UNLOADING_FILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_UNLOADING_FILAMENT_EN, MSG_UNLOADING_FILAMENT_CZ, @@ -2740,12 +3159,27 @@ const char * const MSG_UNLOADING_FILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_UNLOADING_FILAMENT_DE }; +const char MSG_UNLOAD_ALL_EN[] PROGMEM = "Unload all"; +const char MSG_UNLOAD_ALL_CZ[] PROGMEM = "Vyjmout vse"; +const char MSG_UNLOAD_ALL_IT[] PROGMEM = "Rilasciare tutti"; +const char MSG_UNLOAD_ALL_ES[] PROGMEM = "Soltar todos fil."; +const char MSG_UNLOAD_ALL_PL[] PROGMEM = "Wyjac wszystkie"; +const char MSG_UNLOAD_ALL_DE[] PROGMEM = "Alles entladen"; +const char * const MSG_UNLOAD_ALL_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_UNLOAD_ALL_EN, + MSG_UNLOAD_ALL_CZ, + MSG_UNLOAD_ALL_IT, + MSG_UNLOAD_ALL_ES, + MSG_UNLOAD_ALL_PL, + MSG_UNLOAD_ALL_DE +}; + const char MSG_UNLOAD_FILAMENT_EN[] PROGMEM = "Unload filament"; const char MSG_UNLOAD_FILAMENT_CZ[] PROGMEM = "Vyjmout filament"; const char MSG_UNLOAD_FILAMENT_IT[] PROGMEM = "Scarica filamento"; const char MSG_UNLOAD_FILAMENT_ES[] PROGMEM = "Soltar filamento"; const char MSG_UNLOAD_FILAMENT_PL[] PROGMEM = "Wyjac filament"; -const char MSG_UNLOAD_FILAMENT_DE[] PROGMEM = "Entnehm filament"; +const char MSG_UNLOAD_FILAMENT_DE[] PROGMEM = "Filament entladen"; const char * const MSG_UNLOAD_FILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_UNLOAD_FILAMENT_EN, MSG_UNLOAD_FILAMENT_CZ, @@ -2755,18 +3189,94 @@ const char * const MSG_UNLOAD_FILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_UNLOAD_FILAMENT_DE }; +const char MSG_UNLOAD_FILAMENT_1_EN[] PROGMEM = "Unload filament 1"; +const char MSG_UNLOAD_FILAMENT_1_CZ[] PROGMEM = "Vyjmout filam. 1"; +const char MSG_UNLOAD_FILAMENT_1_IT[] PROGMEM = "Rilasciare fil. 1"; +const char MSG_UNLOAD_FILAMENT_1_ES[] PROGMEM = "Soltar fil. 1"; +const char MSG_UNLOAD_FILAMENT_1_PL[] PROGMEM = "Wyjac filament 1"; +const char MSG_UNLOAD_FILAMENT_1_DE[] PROGMEM = "Filam. 1 entladen"; +const char * const MSG_UNLOAD_FILAMENT_1_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_UNLOAD_FILAMENT_1_EN, + MSG_UNLOAD_FILAMENT_1_CZ, + MSG_UNLOAD_FILAMENT_1_IT, + MSG_UNLOAD_FILAMENT_1_ES, + MSG_UNLOAD_FILAMENT_1_PL, + MSG_UNLOAD_FILAMENT_1_DE +}; + +const char MSG_UNLOAD_FILAMENT_2_EN[] PROGMEM = "Unload filament 2"; +const char MSG_UNLOAD_FILAMENT_2_CZ[] PROGMEM = "Vyjmout filam. 2"; +const char MSG_UNLOAD_FILAMENT_2_IT[] PROGMEM = "Rilasciare fil. 1"; +const char MSG_UNLOAD_FILAMENT_2_ES[] PROGMEM = "Soltar fil. 2"; +const char MSG_UNLOAD_FILAMENT_2_PL[] PROGMEM = "Wyjac filament 2"; +const char MSG_UNLOAD_FILAMENT_2_DE[] PROGMEM = "Filam. 2 entladen"; +const char * const MSG_UNLOAD_FILAMENT_2_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_UNLOAD_FILAMENT_2_EN, + MSG_UNLOAD_FILAMENT_2_CZ, + MSG_UNLOAD_FILAMENT_2_IT, + MSG_UNLOAD_FILAMENT_2_ES, + MSG_UNLOAD_FILAMENT_2_PL, + MSG_UNLOAD_FILAMENT_2_DE +}; + +const char MSG_UNLOAD_FILAMENT_3_EN[] PROGMEM = "Unload filament 3"; +const char MSG_UNLOAD_FILAMENT_3_CZ[] PROGMEM = "Vyjmout filam. 3"; +const char MSG_UNLOAD_FILAMENT_3_IT[] PROGMEM = "Rilasciare fil. 1"; +const char MSG_UNLOAD_FILAMENT_3_ES[] PROGMEM = "Soltar fil. 3"; +const char MSG_UNLOAD_FILAMENT_3_PL[] PROGMEM = "Wyjac filament 3"; +const char MSG_UNLOAD_FILAMENT_3_DE[] PROGMEM = "Filam. 3 entladen"; +const char * const MSG_UNLOAD_FILAMENT_3_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_UNLOAD_FILAMENT_3_EN, + MSG_UNLOAD_FILAMENT_3_CZ, + MSG_UNLOAD_FILAMENT_3_IT, + MSG_UNLOAD_FILAMENT_3_ES, + MSG_UNLOAD_FILAMENT_3_PL, + MSG_UNLOAD_FILAMENT_3_DE +}; + +const char MSG_UNLOAD_FILAMENT_4_EN[] PROGMEM = "Unload filament 4"; +const char MSG_UNLOAD_FILAMENT_4_CZ[] PROGMEM = "Vyjmout filam. 4"; +const char MSG_UNLOAD_FILAMENT_4_IT[] PROGMEM = "Rilasciare fil. 1"; +const char MSG_UNLOAD_FILAMENT_4_ES[] PROGMEM = "Soltar fil. 4"; +const char MSG_UNLOAD_FILAMENT_4_PL[] PROGMEM = "Wyjac filament 4"; +const char MSG_UNLOAD_FILAMENT_4_DE[] PROGMEM = "Filam. 4 entladen"; +const char * const MSG_UNLOAD_FILAMENT_4_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_UNLOAD_FILAMENT_4_EN, + MSG_UNLOAD_FILAMENT_4_CZ, + MSG_UNLOAD_FILAMENT_4_IT, + MSG_UNLOAD_FILAMENT_4_ES, + MSG_UNLOAD_FILAMENT_4_PL, + MSG_UNLOAD_FILAMENT_4_DE +}; + const char MSG_USB_PRINTING_EN[] PROGMEM = "USB printing "; const char MSG_USB_PRINTING_CZ[] PROGMEM = "Tisk z USB "; const char MSG_USB_PRINTING_IT[] PROGMEM = "Stampa da USB"; const char MSG_USB_PRINTING_ES[] PROGMEM = "Impresion de USB "; const char MSG_USB_PRINTING_PL[] PROGMEM = "Druk z USB "; +const char MSG_USB_PRINTING_DE[] PROGMEM = "Drucken ueber USB"; const char * const MSG_USB_PRINTING_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_USB_PRINTING_EN, MSG_USB_PRINTING_CZ, MSG_USB_PRINTING_IT, MSG_USB_PRINTING_ES, MSG_USB_PRINTING_PL, - MSG_USB_PRINTING_EN + MSG_USB_PRINTING_DE +}; + +const char MSG_USED_EN[] PROGMEM = "Used during print"; +const char MSG_USED_CZ[] PROGMEM = "Pouzite behem tisku"; +const char MSG_USED_IT[] PROGMEM = "Usati nella stampa"; +const char MSG_USED_ES[] PROGMEM = "Usado en impresion"; +const char MSG_USED_PL[] PROGMEM = "Uzyte przy druku"; +const char MSG_USED_DE[] PROGMEM = "Beim Druck benutzte"; +const char * const MSG_USED_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_USED_EN, + MSG_USED_CZ, + MSG_USED_IT, + MSG_USED_ES, + MSG_USED_PL, + MSG_USED_DE }; const char MSG_USERWAIT_EN[] PROGMEM = "Wait for user..."; @@ -2897,7 +3407,7 @@ const char WELCOME_MSG_CZ[] PROGMEM = CUSTOM_MENDEL_NAME " ok"; const char WELCOME_MSG_IT[] PROGMEM = CUSTOM_MENDEL_NAME " pronta."; const char WELCOME_MSG_ES[] PROGMEM = CUSTOM_MENDEL_NAME " prep."; const char WELCOME_MSG_PL[] PROGMEM = CUSTOM_MENDEL_NAME " gotowa"; -const char WELCOME_MSG_DE[] PROGMEM = CUSTOM_MENDEL_NAME " klar."; +const char WELCOME_MSG_DE[] PROGMEM = CUSTOM_MENDEL_NAME " bereit."; const char * const WELCOME_MSG_LANG_TABLE[LANG_NUM] PROGMEM = { WELCOME_MSG_EN, WELCOME_MSG_CZ, diff --git a/Firmware/language_all.h b/Firmware/language_all.h index 47dde007e..0ca88d66a 100644 --- a/Firmware/language_all.h +++ b/Firmware/language_all.h @@ -1,6 +1,7 @@ #ifndef LANGUAGE_ALL_H #define LANGUAGE_ALL_H +#include // Language indices into their particular symbol tables. #define LANG_ID_EN 0 #define LANG_ID_CZ 1 @@ -29,6 +30,8 @@ extern const char* const MSG_ACTIVE_EXTRUDER_LANG_TABLE[1]; #define MSG_ACTIVE_EXTRUDER LANG_TABLE_SELECT_EXPLICIT(MSG_ACTIVE_EXTRUDER_LANG_TABLE, 0) extern const char* const MSG_ADJUSTZ_LANG_TABLE[LANG_NUM]; #define MSG_ADJUSTZ LANG_TABLE_SELECT(MSG_ADJUSTZ_LANG_TABLE) +extern const char* const MSG_ALL_LANG_TABLE[LANG_NUM]; +#define MSG_ALL LANG_TABLE_SELECT(MSG_ALL_LANG_TABLE) extern const char* const MSG_AMAX_LANG_TABLE[1]; #define MSG_AMAX LANG_TABLE_SELECT_EXPLICIT(MSG_AMAX_LANG_TABLE, 0) extern const char* const MSG_AUTHOR_LANG_TABLE[1]; @@ -61,8 +64,8 @@ extern const char* const MSG_BED_CORRECTION_MENU_LANG_TABLE[LANG_NUM]; #define MSG_BED_CORRECTION_MENU LANG_TABLE_SELECT(MSG_BED_CORRECTION_MENU_LANG_TABLE) extern const char* const MSG_BED_CORRECTION_REAR_LANG_TABLE[LANG_NUM]; #define MSG_BED_CORRECTION_REAR LANG_TABLE_SELECT(MSG_BED_CORRECTION_REAR_LANG_TABLE) -extern const char* const MSG_BED_CORRECTION_RESET_LANG_TABLE[1]; -#define MSG_BED_CORRECTION_RESET LANG_TABLE_SELECT_EXPLICIT(MSG_BED_CORRECTION_RESET_LANG_TABLE, 0) +extern const char* const MSG_BED_CORRECTION_RESET_LANG_TABLE[LANG_NUM]; +#define MSG_BED_CORRECTION_RESET LANG_TABLE_SELECT(MSG_BED_CORRECTION_RESET_LANG_TABLE) extern const char* const MSG_BED_CORRECTION_RIGHT_LANG_TABLE[LANG_NUM]; #define MSG_BED_CORRECTION_RIGHT LANG_TABLE_SELECT(MSG_BED_CORRECTION_RIGHT_LANG_TABLE) extern const char* const MSG_BED_DONE_LANG_TABLE[LANG_NUM]; @@ -107,6 +110,10 @@ extern const char* const MSG_CALIBRATE_BED_RESET_LANG_TABLE[LANG_NUM]; #define MSG_CALIBRATE_BED_RESET LANG_TABLE_SELECT(MSG_CALIBRATE_BED_RESET_LANG_TABLE) extern const char* const MSG_CALIBRATE_E_LANG_TABLE[LANG_NUM]; #define MSG_CALIBRATE_E LANG_TABLE_SELECT(MSG_CALIBRATE_E_LANG_TABLE) +extern const char* const MSG_CALIBRATE_PINDA_LANG_TABLE[LANG_NUM]; +#define MSG_CALIBRATE_PINDA LANG_TABLE_SELECT(MSG_CALIBRATE_PINDA_LANG_TABLE) +extern const char* const MSG_CALIBRATION_PINDA_MENU_LANG_TABLE[LANG_NUM]; +#define MSG_CALIBRATION_PINDA_MENU LANG_TABLE_SELECT(MSG_CALIBRATION_PINDA_MENU_LANG_TABLE) extern const char* const MSG_CARD_MENU_LANG_TABLE[LANG_NUM]; #define MSG_CARD_MENU LANG_TABLE_SELECT(MSG_CARD_MENU_LANG_TABLE) extern const char* const MSG_CHANGE_EXTR_LANG_TABLE[LANG_NUM]; @@ -115,6 +122,8 @@ extern const char* const MSG_CHANGE_SUCCESS_LANG_TABLE[LANG_NUM]; #define MSG_CHANGE_SUCCESS LANG_TABLE_SELECT(MSG_CHANGE_SUCCESS_LANG_TABLE) extern const char* const MSG_CHANGING_FILAMENT_LANG_TABLE[LANG_NUM]; #define MSG_CHANGING_FILAMENT LANG_TABLE_SELECT(MSG_CHANGING_FILAMENT_LANG_TABLE) +extern const char* const MSG_CHOOSE_EXTRUDER_LANG_TABLE[LANG_NUM]; +#define MSG_CHOOSE_EXTRUDER LANG_TABLE_SELECT(MSG_CHOOSE_EXTRUDER_LANG_TABLE) extern const char* const MSG_CLEAN_NOZZLE_E_LANG_TABLE[LANG_NUM]; #define MSG_CLEAN_NOZZLE_E LANG_TABLE_SELECT(MSG_CLEAN_NOZZLE_E_LANG_TABLE) extern const char* const MSG_CNG_SDCARD_LANG_TABLE[1]; @@ -135,6 +144,8 @@ extern const char* const MSG_CORRECTLY_LANG_TABLE[LANG_NUM]; #define MSG_CORRECTLY LANG_TABLE_SELECT(MSG_CORRECTLY_LANG_TABLE) extern const char* const MSG_COUNT_X_LANG_TABLE[1]; #define MSG_COUNT_X LANG_TABLE_SELECT_EXPLICIT(MSG_COUNT_X_LANG_TABLE, 0) +extern const char* const MSG_CURRENT_LANG_TABLE[LANG_NUM]; +#define MSG_CURRENT LANG_TABLE_SELECT(MSG_CURRENT_LANG_TABLE) extern const char* const MSG_DISABLE_STEPPERS_LANG_TABLE[LANG_NUM]; #define MSG_DISABLE_STEPPERS LANG_TABLE_SELECT(MSG_DISABLE_STEPPERS_LANG_TABLE) extern const char* const MSG_DWELL_LANG_TABLE[LANG_NUM]; @@ -169,6 +180,16 @@ extern const char* const MSG_ERR_STOPPED_LANG_TABLE[1]; #define MSG_ERR_STOPPED LANG_TABLE_SELECT_EXPLICIT(MSG_ERR_STOPPED_LANG_TABLE, 0) extern const char* const MSG_EXTERNAL_RESET_LANG_TABLE[1]; #define MSG_EXTERNAL_RESET LANG_TABLE_SELECT_EXPLICIT(MSG_EXTERNAL_RESET_LANG_TABLE, 0) +extern const char* const MSG_EXTRUDER_LANG_TABLE[LANG_NUM]; +#define MSG_EXTRUDER LANG_TABLE_SELECT(MSG_EXTRUDER_LANG_TABLE) +extern const char* const MSG_EXTRUDER_1_LANG_TABLE[LANG_NUM]; +#define MSG_EXTRUDER_1 LANG_TABLE_SELECT(MSG_EXTRUDER_1_LANG_TABLE) +extern const char* const MSG_EXTRUDER_2_LANG_TABLE[LANG_NUM]; +#define MSG_EXTRUDER_2 LANG_TABLE_SELECT(MSG_EXTRUDER_2_LANG_TABLE) +extern const char* const MSG_EXTRUDER_3_LANG_TABLE[LANG_NUM]; +#define MSG_EXTRUDER_3 LANG_TABLE_SELECT(MSG_EXTRUDER_3_LANG_TABLE) +extern const char* const MSG_EXTRUDER_4_LANG_TABLE[LANG_NUM]; +#define MSG_EXTRUDER_4 LANG_TABLE_SELECT(MSG_EXTRUDER_4_LANG_TABLE) extern const char* const MSG_E_CAL_KNOB_LANG_TABLE[LANG_NUM]; #define MSG_E_CAL_KNOB LANG_TABLE_SELECT(MSG_E_CAL_KNOB_LANG_TABLE) extern const char* const MSG_Enqueing_LANG_TABLE[1]; @@ -197,14 +218,14 @@ extern const char* const MSG_FILE_SAVED_LANG_TABLE[1]; #define MSG_FILE_SAVED LANG_TABLE_SELECT_EXPLICIT(MSG_FILE_SAVED_LANG_TABLE, 0) extern const char* const MSG_FIL_ADJUSTING_LANG_TABLE[LANG_NUM]; #define MSG_FIL_ADJUSTING LANG_TABLE_SELECT(MSG_FIL_ADJUSTING_LANG_TABLE) -extern const char* const MSG_FIL_LOADED_CHECK_LANG_TABLE[LANG_NUM]; -#define MSG_FIL_LOADED_CHECK LANG_TABLE_SELECT(MSG_FIL_LOADED_CHECK_LANG_TABLE) -extern const char* const MSG_FIL_TUNING_LANG_TABLE[LANG_NUM]; -#define MSG_FIL_TUNING LANG_TABLE_SELECT(MSG_FIL_TUNING_LANG_TABLE) +extern const char* const MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION_LANG_TABLE[LANG_NUM]; +#define MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION LANG_TABLE_SELECT(MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION_LANG_TABLE) extern const char* const MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_LANG_TABLE[LANG_NUM]; #define MSG_FIND_BED_OFFSET_AND_SKEW_LINE1 LANG_TABLE_SELECT(MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_LANG_TABLE) extern const char* const MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_LANG_TABLE[LANG_NUM]; #define MSG_FIND_BED_OFFSET_AND_SKEW_LINE2 LANG_TABLE_SELECT(MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_LANG_TABLE) +extern const char* const MSG_FINISHING_MOVEMENTS_LANG_TABLE[LANG_NUM]; +#define MSG_FINISHING_MOVEMENTS LANG_TABLE_SELECT(MSG_FINISHING_MOVEMENTS_LANG_TABLE) extern const char* const MSG_FLOW_LANG_TABLE[LANG_NUM]; #define MSG_FLOW LANG_TABLE_SELECT(MSG_FLOW_LANG_TABLE) extern const char* const MSG_FLOW0_LANG_TABLE[1]; @@ -251,10 +272,20 @@ extern const char* const MSG_LOADING_COLOR_LANG_TABLE[LANG_NUM]; #define MSG_LOADING_COLOR LANG_TABLE_SELECT(MSG_LOADING_COLOR_LANG_TABLE) extern const char* const MSG_LOADING_FILAMENT_LANG_TABLE[LANG_NUM]; #define MSG_LOADING_FILAMENT LANG_TABLE_SELECT(MSG_LOADING_FILAMENT_LANG_TABLE) +extern const char* const MSG_LOAD_ALL_LANG_TABLE[LANG_NUM]; +#define MSG_LOAD_ALL LANG_TABLE_SELECT(MSG_LOAD_ALL_LANG_TABLE) extern const char* const MSG_LOAD_EPROM_LANG_TABLE[1]; #define MSG_LOAD_EPROM LANG_TABLE_SELECT_EXPLICIT(MSG_LOAD_EPROM_LANG_TABLE, 0) extern const char* const MSG_LOAD_FILAMENT_LANG_TABLE[LANG_NUM]; #define MSG_LOAD_FILAMENT LANG_TABLE_SELECT(MSG_LOAD_FILAMENT_LANG_TABLE) +extern const char* const MSG_LOAD_FILAMENT_1_LANG_TABLE[LANG_NUM]; +#define MSG_LOAD_FILAMENT_1 LANG_TABLE_SELECT(MSG_LOAD_FILAMENT_1_LANG_TABLE) +extern const char* const MSG_LOAD_FILAMENT_2_LANG_TABLE[LANG_NUM]; +#define MSG_LOAD_FILAMENT_2 LANG_TABLE_SELECT(MSG_LOAD_FILAMENT_2_LANG_TABLE) +extern const char* const MSG_LOAD_FILAMENT_3_LANG_TABLE[LANG_NUM]; +#define MSG_LOAD_FILAMENT_3 LANG_TABLE_SELECT(MSG_LOAD_FILAMENT_3_LANG_TABLE) +extern const char* const MSG_LOAD_FILAMENT_4_LANG_TABLE[LANG_NUM]; +#define MSG_LOAD_FILAMENT_4 LANG_TABLE_SELECT(MSG_LOAD_FILAMENT_4_LANG_TABLE) extern const char* const MSG_LOOSE_PULLEY_LANG_TABLE[LANG_NUM]; #define MSG_LOOSE_PULLEY LANG_TABLE_SELECT(MSG_LOOSE_PULLEY_LANG_TABLE) extern const char* const MSG_M104_INVALID_EXTRUDER_LANG_TABLE[1]; @@ -343,6 +374,16 @@ extern const char* const MSG_PAUSE_PRINT_LANG_TABLE[LANG_NUM]; #define MSG_PAUSE_PRINT LANG_TABLE_SELECT(MSG_PAUSE_PRINT_LANG_TABLE) extern const char* const MSG_PICK_Z_LANG_TABLE[LANG_NUM]; #define MSG_PICK_Z LANG_TABLE_SELECT(MSG_PICK_Z_LANG_TABLE) +extern const char* const MSG_PID_EXTRUDER_LANG_TABLE[LANG_NUM]; +#define MSG_PID_EXTRUDER LANG_TABLE_SELECT(MSG_PID_EXTRUDER_LANG_TABLE) +extern const char* const MSG_PID_FINISHED_LANG_TABLE[LANG_NUM]; +#define MSG_PID_FINISHED LANG_TABLE_SELECT(MSG_PID_FINISHED_LANG_TABLE) +extern const char* const MSG_PID_RUNNING_LANG_TABLE[LANG_NUM]; +#define MSG_PID_RUNNING LANG_TABLE_SELECT(MSG_PID_RUNNING_LANG_TABLE) +extern const char* const MSG_PINDA_NOT_CALIBRATED_LANG_TABLE[LANG_NUM]; +#define MSG_PINDA_NOT_CALIBRATED LANG_TABLE_SELECT(MSG_PINDA_NOT_CALIBRATED_LANG_TABLE) +extern const char* const MSG_PINDA_PREHEAT_LANG_TABLE[LANG_NUM]; +#define MSG_PINDA_PREHEAT LANG_TABLE_SELECT(MSG_PINDA_PREHEAT_LANG_TABLE) extern const char* const MSG_PLANNER_BUFFER_BYTES_LANG_TABLE[1]; #define MSG_PLANNER_BUFFER_BYTES LANG_TABLE_SELECT_EXPLICIT(MSG_PLANNER_BUFFER_BYTES_LANG_TABLE, 0) extern const char* const MSG_PLEASE_WAIT_LANG_TABLE[LANG_NUM]; @@ -355,12 +396,16 @@ extern const char* const MSG_PREHEAT_LANG_TABLE[LANG_NUM]; #define MSG_PREHEAT LANG_TABLE_SELECT(MSG_PREHEAT_LANG_TABLE) extern const char* const MSG_PREHEAT_NOZZLE_LANG_TABLE[LANG_NUM]; #define MSG_PREHEAT_NOZZLE LANG_TABLE_SELECT(MSG_PREHEAT_NOZZLE_LANG_TABLE) +extern const char* const MSG_PREPARE_FILAMENT_LANG_TABLE[LANG_NUM]; +#define MSG_PREPARE_FILAMENT LANG_TABLE_SELECT(MSG_PREPARE_FILAMENT_LANG_TABLE) extern const char* const MSG_PRESS_LANG_TABLE[LANG_NUM]; #define MSG_PRESS LANG_TABLE_SELECT(MSG_PRESS_LANG_TABLE) extern const char* const MSG_PRINTER_DISCONNECTED_LANG_TABLE[1]; #define MSG_PRINTER_DISCONNECTED LANG_TABLE_SELECT_EXPLICIT(MSG_PRINTER_DISCONNECTED_LANG_TABLE, 0) extern const char* const MSG_PRINT_ABORTED_LANG_TABLE[LANG_NUM]; #define MSG_PRINT_ABORTED LANG_TABLE_SELECT(MSG_PRINT_ABORTED_LANG_TABLE) +extern const char* const MSG_PRINT_PAUSED_LANG_TABLE[LANG_NUM]; +#define MSG_PRINT_PAUSED LANG_TABLE_SELECT(MSG_PRINT_PAUSED_LANG_TABLE) extern const char* const MSG_PRUSA3D_LANG_TABLE[LANG_NUM]; #define MSG_PRUSA3D LANG_TABLE_SELECT(MSG_PRUSA3D_LANG_TABLE) extern const char* const MSG_PRUSA3D_FORUM_LANG_TABLE[LANG_NUM]; @@ -383,6 +428,8 @@ extern const char* const MSG_RESUME_PRINT_LANG_TABLE[LANG_NUM]; #define MSG_RESUME_PRINT LANG_TABLE_SELECT(MSG_RESUME_PRINT_LANG_TABLE) extern const char* const MSG_RESUMING_LANG_TABLE[LANG_NUM]; #define MSG_RESUMING LANG_TABLE_SELECT(MSG_RESUMING_LANG_TABLE) +extern const char* const MSG_RESUMING_PRINT_LANG_TABLE[LANG_NUM]; +#define MSG_RESUMING_PRINT LANG_TABLE_SELECT(MSG_RESUMING_PRINT_LANG_TABLE) extern const char* const MSG_SD_CANT_ENTER_SUBDIR_LANG_TABLE[1]; #define MSG_SD_CANT_ENTER_SUBDIR LANG_TABLE_SELECT_EXPLICIT(MSG_SD_CANT_ENTER_SUBDIR_LANG_TABLE, 0) extern const char* const MSG_SD_CANT_OPEN_SUBDIR_LANG_TABLE[1]; @@ -477,6 +524,8 @@ extern const char* const MSG_SET_HOME_OFFSETS_LANG_TABLE[1]; #define MSG_SET_HOME_OFFSETS LANG_TABLE_SELECT_EXPLICIT(MSG_SET_HOME_OFFSETS_LANG_TABLE, 0) extern const char* const MSG_SET_ORIGIN_LANG_TABLE[1]; #define MSG_SET_ORIGIN LANG_TABLE_SELECT_EXPLICIT(MSG_SET_ORIGIN_LANG_TABLE, 0) +extern const char* const MSG_SET_TEMPERATURE_LANG_TABLE[LANG_NUM]; +#define MSG_SET_TEMPERATURE LANG_TABLE_SELECT(MSG_SET_TEMPERATURE_LANG_TABLE) extern const char* const MSG_SHOW_END_STOPS_LANG_TABLE[LANG_NUM]; #define MSG_SHOW_END_STOPS LANG_TABLE_SELECT(MSG_SHOW_END_STOPS_LANG_TABLE) extern const char* const MSG_SILENT_MODE_OFF_LANG_TABLE[LANG_NUM]; @@ -517,6 +566,14 @@ extern const char* const MSG_TAKE_EFFECT_LANG_TABLE[LANG_NUM]; #define MSG_TAKE_EFFECT LANG_TABLE_SELECT(MSG_TAKE_EFFECT_LANG_TABLE) extern const char* const MSG_TEMPERATURE_LANG_TABLE[LANG_NUM]; #define MSG_TEMPERATURE LANG_TABLE_SELECT(MSG_TEMPERATURE_LANG_TABLE) +extern const char* const MSG_TEMP_CALIBRATION_LANG_TABLE[LANG_NUM]; +#define MSG_TEMP_CALIBRATION LANG_TABLE_SELECT(MSG_TEMP_CALIBRATION_LANG_TABLE) +extern const char* const MSG_TEMP_CALIBRATION_DONE_LANG_TABLE[LANG_NUM]; +#define MSG_TEMP_CALIBRATION_DONE LANG_TABLE_SELECT(MSG_TEMP_CALIBRATION_DONE_LANG_TABLE) +extern const char* const MSG_TEMP_CALIBRATION_OFF_LANG_TABLE[LANG_NUM]; +#define MSG_TEMP_CALIBRATION_OFF LANG_TABLE_SELECT(MSG_TEMP_CALIBRATION_OFF_LANG_TABLE) +extern const char* const MSG_TEMP_CALIBRATION_ON_LANG_TABLE[LANG_NUM]; +#define MSG_TEMP_CALIBRATION_ON LANG_TABLE_SELECT(MSG_TEMP_CALIBRATION_ON_LANG_TABLE) extern const char* const MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF_LANG_TABLE[LANG_NUM]; #define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF LANG_TABLE_SELECT(MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF_LANG_TABLE) extern const char* const MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON_LANG_TABLE[LANG_NUM]; @@ -527,10 +584,22 @@ extern const char* const MSG_UNKNOWN_COMMAND_LANG_TABLE[1]; #define MSG_UNKNOWN_COMMAND LANG_TABLE_SELECT_EXPLICIT(MSG_UNKNOWN_COMMAND_LANG_TABLE, 0) extern const char* const MSG_UNLOADING_FILAMENT_LANG_TABLE[LANG_NUM]; #define MSG_UNLOADING_FILAMENT LANG_TABLE_SELECT(MSG_UNLOADING_FILAMENT_LANG_TABLE) +extern const char* const MSG_UNLOAD_ALL_LANG_TABLE[LANG_NUM]; +#define MSG_UNLOAD_ALL LANG_TABLE_SELECT(MSG_UNLOAD_ALL_LANG_TABLE) extern const char* const MSG_UNLOAD_FILAMENT_LANG_TABLE[LANG_NUM]; #define MSG_UNLOAD_FILAMENT LANG_TABLE_SELECT(MSG_UNLOAD_FILAMENT_LANG_TABLE) +extern const char* const MSG_UNLOAD_FILAMENT_1_LANG_TABLE[LANG_NUM]; +#define MSG_UNLOAD_FILAMENT_1 LANG_TABLE_SELECT(MSG_UNLOAD_FILAMENT_1_LANG_TABLE) +extern const char* const MSG_UNLOAD_FILAMENT_2_LANG_TABLE[LANG_NUM]; +#define MSG_UNLOAD_FILAMENT_2 LANG_TABLE_SELECT(MSG_UNLOAD_FILAMENT_2_LANG_TABLE) +extern const char* const MSG_UNLOAD_FILAMENT_3_LANG_TABLE[LANG_NUM]; +#define MSG_UNLOAD_FILAMENT_3 LANG_TABLE_SELECT(MSG_UNLOAD_FILAMENT_3_LANG_TABLE) +extern const char* const MSG_UNLOAD_FILAMENT_4_LANG_TABLE[LANG_NUM]; +#define MSG_UNLOAD_FILAMENT_4 LANG_TABLE_SELECT(MSG_UNLOAD_FILAMENT_4_LANG_TABLE) extern const char* const MSG_USB_PRINTING_LANG_TABLE[LANG_NUM]; #define MSG_USB_PRINTING LANG_TABLE_SELECT(MSG_USB_PRINTING_LANG_TABLE) +extern const char* const MSG_USED_LANG_TABLE[LANG_NUM]; +#define MSG_USED LANG_TABLE_SELECT(MSG_USED_LANG_TABLE) extern const char* const MSG_USERWAIT_LANG_TABLE[LANG_NUM]; #define MSG_USERWAIT LANG_TABLE_SELECT(MSG_USERWAIT_LANG_TABLE) extern const char* const MSG_VMIN_LANG_TABLE[1]; diff --git a/Firmware/language_cz.h b/Firmware/language_cz.h index 9dda46c22..5f2e36af5 100644 --- a/Firmware/language_cz.h +++ b/Firmware/language_cz.h @@ -73,7 +73,17 @@ #define MSG_SETTINGS "Nastaveni" #define MSG_PREHEAT "Predehrev" #define MSG_UNLOAD_FILAMENT "Vyjmout filament" -#define MSG_LOAD_FILAMENT "Zavest filament" +#define MSG_LOAD_FILAMENT "Zavest filament" +#define MSG_LOAD_FILAMENT_1 "Zavest filament 1" +#define MSG_LOAD_FILAMENT_2 "Zavest filament 2" +#define MSG_LOAD_FILAMENT_3 "Zavest filament 3" +#define MSG_LOAD_FILAMENT_4 "Zavest filament 4" +#define MSG_UNLOAD_FILAMENT_1 "Vyjmout filam. 1" +#define MSG_UNLOAD_FILAMENT_2 "Vyjmout filam. 2" +#define MSG_UNLOAD_FILAMENT_3 "Vyjmout filam. 3" +#define MSG_UNLOAD_FILAMENT_4 "Vyjmout filam. 4" +#define MSG_UNLOAD_ALL "Vyjmout vse" +#define MSG_LOAD_ALL "Zavest vse" #define MSG_RECTRACT "Rectract" #define MSG_ERROR "CHYBA:" @@ -212,6 +222,7 @@ #define MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2 " z 9" #define MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1 "Merim referencni vysku kalibracniho bodu" #define MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2 " z 9" +#define MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION "Iterace " #define MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND "Kalibrace XYZ selhala. Kalibracni bod podlozky nenalezen." #define MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED "Kalibrace XYZ selhala. Nahlednete do manualu." @@ -247,13 +258,12 @@ #define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON "SD card [FlshAir]" #define MSG_LOOSE_PULLEY "Uvolnena remenicka" -#define MSG_FILAMENT_LOADING_T0 "Vložte filament do extruderu 1. Potvrdte tlacitkem." -#define MSG_FILAMENT_LOADING_T1 "Vložte filament do extruderu 2. Potvrdte tlacitkem." -#define MSG_FILAMENT_LOADING_T2 "Vložte filament do extruderu 3. Potvrdte tlacitkem." -#define MSG_FILAMENT_LOADING_T3 "Vložte filament do extruderu 4. Potvrdte tlacitkem." +#define MSG_FILAMENT_LOADING_T0 "Vlozte filament do extruderu 1. Potvrdte tlacitkem." +#define MSG_FILAMENT_LOADING_T1 "Vlozte filament do extruderu 2. Potvrdte tlacitkem." +#define MSG_FILAMENT_LOADING_T2 "Vlozte filament do extruderu 3. Potvrdte tlacitkem." +#define MSG_FILAMENT_LOADING_T3 "Vlozte filament do extruderu 4. Potvrdte tlacitkem." #define MSG_CHANGE_EXTR "Zmenit extruder" -#define MSG_FIL_LOADED_CHECK "Je filament zaveden?" -#define MSG_FIL_TUNING "Otacenim tlacitka doladte pozici filamentu." + #define MSG_FIL_ADJUSTING "Probiha srovnani filamentu. Prosim cekejte." #define MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ "Filamenty jsou srovnany. Pro uspesnou kalibraci prosim ocistete trysku. Po te potvrdte tlacitkem." #define MSG_CALIBRATE_E "Kalibrovat E" @@ -264,4 +274,31 @@ #define MSG_FILAMENT_CLEAN "Je barva cista?" #define MSG_UNLOADING_FILAMENT "Vysouvam filament" -#define MSG_PAPER "Umistete list papiru na podlozku a udrzujte jej pod tryskou behem mereni prvnich 4 bodu. Pokud tryska zachyti papir, vypnete tiskarnu." \ No newline at end of file +#define MSG_PAPER "Umistete list papiru na podlozku a udrzujte jej pod tryskou behem mereni prvnich 4 bodu. Pokud tryska zachyti papir, vypnete tiskarnu." + +#define MSG_FINISHING_MOVEMENTS "Dokoncovani pohybu" +#define MSG_PRINT_PAUSED "Tisk pozastaven" +#define MSG_RESUMING_PRINT "Obnovovani tisku" +#define MSG_PID_EXTRUDER "PID kalibrace" +#define MSG_SET_TEMPERATURE "Nastavte teplotu:" +#define MSG_PID_FINISHED "PID kal. ukoncena" +#define MSG_PID_RUNNING "PID kal. " + +#define MSG_CALIBRATE_PINDA "Zkalibrovat" +#define MSG_CALIBRATION_PINDA_MENU "Teplot. kalibrace" +#define MSG_PINDA_NOT_CALIBRATED "Tiskarna nebyla teplotne zkalibrovana" +#define MSG_PINDA_PREHEAT "Nahrivani PINDA" +#define MSG_TEMP_CALIBRATION "Tepl. kal. " +#define MSG_TEMP_CALIBRATION_DONE "Teplotni kalibrace dokoncena. Pokracujte stiskem tlacitka." +#define MSG_TEMP_CALIBRATION_ON "Tepl. kal. [ON]" +#define MSG_TEMP_CALIBRATION_OFF "Tepl. kal. [OFF]" +#define MSG_PREPARE_FILAMENT "Pripravte filament" +#define MSG_ALL "Vse" +#define MSG_USED "Pouzite behem tisku" +#define MSG_CURRENT "Pouze aktualni" +#define MSG_CHOOSE_EXTRUDER "Vyberte extruder:" +#define MSG_EXTRUDER "Extruder" +#define MSG_EXTRUDER_1 "Extruder 1" +#define MSG_EXTRUDER_2 "Extruder 2" +#define MSG_EXTRUDER_3 "Extruder 3" +#define MSG_EXTRUDER_4 "Extruder 4" \ No newline at end of file diff --git a/Firmware/language_de.h b/Firmware/language_de.h new file mode 100644 index 000000000..fe5f41825 --- /dev/null +++ b/Firmware/language_de.h @@ -0,0 +1,317 @@ ++/** + + * German + + * + + * LCD Menu Messages + + * Please note these are limited to 17 characters! + + * + + */ + + + +#define(length = 20) WELCOME_MSG CUSTOM_MENDEL_NAME " bereit." + + #define MSG_SD_INSERTED "SD eingesetzt" + + #define MSG_SD_REMOVED "SD entfernt " + + #define MSG_MAIN "Hauptmenue" + + #define MSG_DISABLE_STEPPERS "Motoren aus" + + #define MSG_AUTO_HOME "Startposition" + + #define MSG_SET_HOME_OFFSETS "Abstand vom Ursprung einstellen" + + #define MSG_SET_ORIGIN "Ursprung einstellen" + + #define MSG_COOLDOWN "Abkuehlen" + + #define MSG_SWITCH_PS_ON "Netzteil EIN" + + #define MSG_SWITCH_PS_OFF "Netzteil AUS" + + #define MSG_MOVE_AXIS "Achsbewegung" + + #define MSG_MOVE_X "Bewege X" + + #define MSG_MOVE_Y "Bewege Y" + + #define MSG_MOVE_Z "Bewege Z" + + #define MSG_MOVE_E "Extruder" + + #define MSG_SPEED "Geschwindigkeit" + + #define MSG_NOZZLE "Duese" + + #define MSG_NOZZLE1 "Duese2" + + #define MSG_NOZZLE2 "Duese3" + + #define MSG_BED "Bed" + + #define MSG_FAN_SPEED "Luefter-Tempo" + + #define MSG_FLOW "Durchfluss" + + #define MSG_FLOW0 "Durchfluss 0" + + #define MSG_FLOW1 "Durchfluss 1" + + #define MSG_FLOW2 "Durchfluss 2" + + #define MSG_CONTROL "Kontrolle" + + #define MSG_MIN " \002 Min" + + #define MSG_MAX " \002 Max" + + #define MSG_FACTOR " \002 Fakt" + + #define MSG_TEMPERATURE "Temperatur" + + #define MSG_MOTION "Bewegung" + + #define MSG_VOLUMETRIC "Filament" + + #define MSG_VOLUMETRIC_ENABLED "E in mm3" + + #define MSG_STORE_EPROM "Abspeichern" + + #define MSG_LOAD_EPROM "Lade Speicher" + + #define MSG_RESTORE_FAILSAFE "Standardwerte setzen" + + #define MSG_REFRESH "\xF8" "Erneuern" + + #define MSG_WATCH "Information" + + #define MSG_TUNE "Feineinstellung" + + #define MSG_PAUSE_PRINT "Druck unterbrech." + + #define MSG_RESUME_PRINT "Fortsetzen" + + #define MSG_STOP_PRINT "Druck abbrechen" + + #define MSG_CARD_MENU "Drucken von SD" + + #define MSG_NO_CARD "Keine SD Karte" + + #define MSG_DWELL "Einen Moment bitte." + + #define MSG_USERWAIT "Warte auf user..." + + #define MSG_RESUMING "Druck fortgesetzt" + + #define(length = 20) MSG_PRINT_ABORTED "Druck abgebrochen" + + #define MSG_NO_MOVE "Keine Bewegung." + + #define MSG_KILLED "ABGEBROCHEN. " + + #define MSG_STOPPED "GESTOPPT. " + + #define MSG_FILAMENTCHANGE "Filament-Wechsel" + + #define MSG_INIT_SDCARD "Init SD Karte" + + #define MSG_CNG_SDCARD "Wechsel SD Karte" + + #define MSG_BABYSTEP_X "Babystep X" + + #define MSG_BABYSTEP_Y "Babystep Y" + + #define MSG_BABYSTEP_Z "Z einstellen" + + #define MSG_ADJUSTZ "Auto Z einstellen?" + + #define MSG_PICK_Z "Waehle Abdruck" + + + +#define MSG_SETTINGS "Einstellungen" + + #define MSG_PREHEAT "Vorwaermen" + + #define MSG_UNLOAD_FILAMENT "Filament entladen" + + #define MSG_LOAD_FILAMENT "Filament laden" + + + +#define MSG_RECTRACT "Retract" + + #define MSG_ERROR "FEHLER:" + + #define(length = 20) MSG_PREHEAT_NOZZLE "Duese Vorwaermen" + + #define MSG_SUPPORT "Support" + + #define(length = 20) MSG_CORRECTLY "Wechsel ok?" + + #define MSG_YES "Ja" + + #define MSG_NO "Nein" + + #define(length = 19) MSG_NOT_LOADED "Fil. nicht geladen" + + #define MSG_NOT_COLOR "Farbe unklar" + + #define(length = 20) MSG_LOADING_FILAMENT "Filament leadt" + + #define(length = 20) MSG_PLEASE_WAIT "Bitte warten" + + #define MSG_LOADING_COLOR "Lade Farbe" + + #define MSG_CHANGE_SUCCESS "Wechsel erfolgr.!" + + #define(length = 20) MSG_PRESS "und Knopf druecken" + + #define(length = 20) MSG_INSERT_FILAMENT "Filament einlegen" + + #define(length = 20) MSG_CHANGING_FILAMENT "Filament-Wechsel!" + + + + + +#define MSG_SILENT_MODE_ON "Mode [leise]" + + #define MSG_SILENT_MODE_OFF "Mode [Hohe Leist]" + + #define(length = 20) MSG_REBOOT "Zum Uebernehmen " + + #define(length = 22) MSG_TAKE_EFFECT "Drucker neu starten" + + + +#define MSG_Enqueing "enqueuing \" + + #define MSG_POWERUP "Einschalten" + + #define MSG_CONFIGURATION_VER " Letztes Update:" + + #define MSG_FREE_MEMORY " Freier Speicher: " + + #define MSG_PLANNER_BUFFER_BYTES " PlannerBufferBytes: " + + #define MSG_OK "ok" + + #define MSG_ERR_CHECKSUM_MISMATCH "Pruefsummenfehler, Letzte Zeile: " //Checksum Fehler, Letzte Zeile: " + + #define MSG_ERR_NO_CHECKSUM "Keine Pruefsumme mit Zeilennummer, Letzte Zeile: " //Keine Checksum mit Zeilennummer, Letzte Zeile: " + + #define MSG_BEGIN_FILE_LIST "Beginn Dateiliste" + + #define MSG_END_FILE_LIST "Ende Dateiliste" + + #define MSG_M104_INVALID_EXTRUDER "M104 Falscher Extruder" + + #define MSG_M105_INVALID_EXTRUDER "M105 Falscher Extruder" + + #define MSG_M200_INVALID_EXTRUDER "M200 Falscher Extruder" + + #define MSG_M218_INVALID_EXTRUDER "M218 Falscher Extruder" + + #define MSG_M221_INVALID_EXTRUDER "M221 Falscher Extruder" + + #define MSG_ERR_NO_THERMISTORS "Keine Thermistoren - keine Temperatur" + + #define MSG_M109_INVALID_EXTRUDER "M109 Falscher Extruder" + + #define MSG_HEATING "Aufwaermen" + + #define(length = 20) MSG_HEATING_COMPLETE "Aufwaermen OK" + + #define MSG_BED_HEATING "Bed aufwaermen" + + #define MSG_BED_DONE "Bed OK" + + #define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1.0.2; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" CUSTOM_MENDEL_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID "\n" + + #define MSG_ERR_KILLED "Printer gestoppt. kill() aufgerufen!" + + #define MSG_ERR_STOPPED "Drucker aufgrund von Fehlern gestoppt. Fehler beheben und mit M999 neu starten. (Temperatur wird zurueckgesetzt. Nach dem Neustart neu einstellen!)" + + #define MSG_RESEND "Wiederholen: " + + #define MSG_M119_REPORT "Statusbericht Endanschlag" + + #define MSG_ENDSTOP_HIT "AUSGELOEST" + + #define MSG_ENDSTOP_OPEN "offen" + + + +#define MSG_SD_CANT_OPEN_SUBDIR "Kann Unterverz. nicht oeffnen" + + #define MSG_SD_INIT_FAIL "SD Init fehlerhaft" + + #define MSG_SD_VOL_INIT_FAIL "Dateisystem Init fehlerhaft" + + #define MSG_SD_OPENROOT_FAIL "Zugriff auf Basisverzeichnis misslungen" + + #define MSG_SD_CARD_OK "SD Karte ok" + + #define MSG_SD_WORKDIR_FAIL "Oeffnen Arbeitsverzeichnis misslungen" + + #define MSG_SD_OPEN_FILE_FAIL "Fehler beim Oeffnen der Datei: " + + #define MSG_SD_FILE_OPENED "Datei geoeffnet: " + + #define MSG_SD_FILE_SELECTED "Datei ausgewaehlt" + + #define MSG_SD_WRITE_TO_FILE "Schreiben der Datei: " + + #define MSG_SD_PRINTING_BYTE "SD printing byte " + + #define MSG_SD_NOT_PRINTING "Kein SD Print" + + #define MSG_SD_ERR_WRITE_TO_FILE "Fehler beim Schreiben in Datei" + + #define MSG_SD_CANT_ENTER_SUBDIR "Zugangsproblem Unterverzeichnis: " + + #define MSG_STEPPER_TOO_HIGH "Schrittrate zu hoch" + + #define MSG_ENDSTOPS_HIT "Endanschlag erreicht" + + #define MSG_ERR_COLD_EXTRUDE_STOP "Stopp, Extruder kalt!" + + #define MSG_BABYSTEPPING_X "Babystepping X" + + #define MSG_BABYSTEPPING_Y "Babystepping Y" + + #define MSG_BABYSTEPPING_Z "Z wurde eingestellt" + + #define MSG_SERIAL_ERROR_MENU_STRUCTURE "Menuestruktur fehlerhaft" + + + +#define MSG_LANGUAGE_NAME "Deutsch" + + #define MSG_LANGUAGE_SELECT "Waehle Sprache" + + #define MSG_PRUSA3D "prusa3d.com" + + #define MSG_PRUSA3D_FORUM "forum.prusa3d.com" + + #define MSG_PRUSA3D_HOWTO "howto.prusa3d.com" + + + +#define MSG_SELFTEST_ERROR "Selbtest Fehler!" + + #define MSG_SELFTEST_PLEASECHECK "Bitte pruefe:" + + #define MSG_SELFTEST_NOTCONNECTED "Nicht angeschlossen" + + #define MSG_SELFTEST_HEATERTHERMISTOR "Heater/Thermistor" + + #define MSG_SELFTEST_BEDHEATER "Bed / Heater" + + #define MSG_SELFTEST_WIRINGERROR "Verdrahtungfehler" + + #define MSG_SELFTEST_ENDSTOPS "Endschalter" + + #define MSG_SELFTEST_MOTOR "Motor" + + #define MSG_SELFTEST_ENDSTOP "Endstop" + + #define MSG_SELFTEST_ENDSTOP_NOTHIT "Ende nicht getrof." + + #define MSG_SELFTEST_OK "Selbsttest OK" + + #define MSG_LOOSE_PULLEY "Lose Riemenscheibe" + + + +#define MSG_SELFTEST_FAN "Lueftertest" ++#define(length = 20) MSG_SELFTEST_COOLING_FAN "Vorderer Luefter?" ++#define(length = 20) MSG_SELFTEST_EXTRUDER_FAN "Linker Luefter?" ++#define MSG_SELFTEST_FAN_YES "Dreht" ++#define MSG_SELFTEST_FAN_NO "Dreht nicht" ++ ++#define(length = 20) MSG_STATS_TOTALFILAMENT "Gesamtfilament:" ++ #define(length = 20) MSG_STATS_TOTALPRINTTIME "Totale Druckzeit:" ++ #define(length = 20) MSG_STATS_FILAMENTUSED "Filamentverbrauch:" ++ #define(length = 20) MSG_STATS_PRINTTIME "Druckzeit: " ++ #define(length = 20) MSG_SELFTEST_START "Selbsttest start " ++ #define(length = 20) MSG_SELFTEST_CHECK_ENDSTOPS "Pruefe Endschalter " ++ #define(length = 20) MSG_SELFTEST_CHECK_HOTEND "Pruefe Hotend" ++ #define(length = 20) MSG_SELFTEST_CHECK_X "Pruefe X Achse " ++ #define(length = 20) MSG_SELFTEST_CHECK_Y "Pruefe Y Achse " ++ #define(length = 20) MSG_SELFTEST_CHECK_Z "Pruefe Z Achse " ++ #define(length = 20) MSG_SELFTEST_CHECK_BED "Pr\x81fe Bed " ++ #define(length = 20) MSG_SELFTEST_CHECK_ALLCORRECT "Alles richtig " ++ #define MSG_SELFTEST "Selbsttest " ++ #define(length = 20) MSG_SELFTEST_FAILED "Selbsttest misslung." ++ #define MSG_STATISTICS "Statistiken " ++ #define MSG_USB_PRINTING "Drucken ueber USB" ++ #define MSG_HOMEYZ "Kalibrieren Z" ++ #define MSG_HOMEYZ_PROGRESS "Kalibriere Z" ++ #define MSG_HOMEYZ_DONE "Kalibrierung OK" ++ ++#define MSG_SHOW_END_STOPS "Endschalter Stat." ++ #define MSG_CALIBRATE_BED "Kalibrierung XYZ" ++ #define MSG_CALIBRATE_BED_RESET "Reset XYZ Kalibr." ++ + ++#define(length = 20, lines = 8) MSG_MOVE_CARRIAGE_TO_THE_TOP "Kalibrieren von XYZ. Drehen Sie den Knopf bis der obere Anschlag erreicht wird. Klicken wenn ganz oben." ++ #define(length = 20, lines = 8) MSG_MOVE_CARRIAGE_TO_THE_TOP_Z "Kalibrieren von Z. Drehen Sie den Knopf bis der obere Anschlag erreicht wird. Klicken wenn ganz oben." ++ + ++#define(length = 20, lines = 8) MSG_CONFIRM_NOZZLE_CLEAN "Bitte entfernen Sie ueberstehendes Filament von der Duese. Klicken wenn sauber." ++ #define(length = 20, lines = 2) MSG_CONFIRM_CARRIAGE_AT_THE_TOP "Ist der Schlitten ganz oben?" ++ ++#define(length = 60) MSG_FIND_BED_OFFSET_AND_SKEW_LINE1 "Suchen Bed Kalibrierpunkt" ++ #define(length = 14) MSG_FIND_BED_OFFSET_AND_SKEW_LINE2 " von 4" ++ #define(length = 60) MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1 "Verbesserung Bed Kalibrierpunkt" ++ #define(length = 14) MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2 " von 9" ++ #define(length = 60) MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1 "Messen der Referenzhoehe des Kalibrierpunktes" ++ #define(length = 14) MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2 " von 9" +#define MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION "Iteration " ++ ++#define(length = 20, lines = 8) MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND "XYZ-Kalibrierung fehlgeschlagen. Bed-Kalibrierpunkt nicht gefunden." ++ #define(length = 20, lines = 8) MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED "XYZ-Kalibrierung fehlgeschlagen. Bitte schauen Sie in das Handbuch." + ++ #define(length = 20, lines = 8) MSG_BED_SKEW_OFFSET_DETECTION_PERFECT "XYZ-Kalibrierung ok. X/Y-Achsen sind senkrecht zueinander. Glueckwunsch!" ++ #define(length = 20, lines = 8) MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD "XYZ Kalibrierung in Ordnung. X/Y Achsen sind etwas schief." ++ #define(length = 20, lines = 8) MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME "XYZ Kalibrierung in Ordnung. Schiefheit wird automatisch korrigiert." + ++ #define(length = 20, lines = 8) MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR "XYZ-Kalibrierung fehlgeschlagen. Linker vorderer Kalibrierpunkt ist zu weit vorne." ++ #define(length = 20, lines = 8) MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR "XYZ-Kalibrierung fehlgeschlagen. Rechter vorderer Kalibrierpunkt ist zu weit vorne." ++ #define(length = 20, lines = 8) MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR "XYZ-Kalibrierung fehlgeschlagen. Vordere Kalibrierpunkte sind zu weit vorne." ++ #define(length = 20, lines = 8) MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR "XYZ-Kalibrierung ungenau. Linker vorderer Kalibrierpunkt ist zu weit vorne." ++ #define(length = 20, lines = 8) MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR "XYZ-Kalibrierung ungenau. Rechter vorderer Kalibrierpunkt ist zu weit vorne." ++ #define(length = 20, lines = 8) MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR "XYZ-Kalibrierung ungenau. Vordere Kalibrierpunkte sind zu weit vorne." ++ ++#define(length = 20, lines = 4) MSG_BED_LEVELING_FAILED_POINT_LOW "Z-Kal. fehlgeschlg. Sensor nicht ausgeloest. Schmutzige Duese? Warte auf Reset" + ++ #define(length = 20, lines = 4) MSG_BED_LEVELING_FAILED_POINT_HIGH "Z-Kalibrierung fehlgeschlg. Sensor zu hoch ausgeloest. Warte auf Reset." ++ #define(length = 20, lines = 4) MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED "Z-Kalibrierung fehlgeschlg. Sensor nicht angeschlossen. Warte auf Reset." ++ ++#define(length = 20, lines = 2) MSG_NEW_FIRMWARE_AVAILABLE "Neue Firmware Version verfuegbar:" ++ #define(length = 20) MSG_NEW_FIRMWARE_PLEASE_UPGRADE "Bitte aktualisieren." ++ ++ #define(length = 20, lines = 8) MSG_FOLLOW_CALIBRATION_FLOW "Der Drucker wurde noch nicht kalibriert. Bitte folgen Sie dem Handbuch, Kapitel First steps, Abschnitt Calibration flow." ++ #define(length = 20, lines = 12) MSG_BABYSTEP_Z_NOT_SET "Der Abstand zwischen der Spitze der Duese und der Bed ist noch nicht eingestellt. Bitte folgen Sie dem Handbuch, First steps, section First layer calibration." ++ ++ + ++ #define(length = 20, lines = 4) MSG_FILAMENT_LOADING_T0 "Filament in extruder 1 einlegen. Klicken wenn fertig." ++ #define(length = 20, lines = 4) MSG_FILAMENT_LOADING_T1 "Filament in extruder 2 einlegen. Klicken wenn fertig." ++ #define(length = 20, lines = 4) MSG_FILAMENT_LOADING_T2 "Filament in extruder 3 einlegen. Klicken wenn fertig." ++ #define(length = 20, lines = 4) MSG_FILAMENT_LOADING_T3 "Filament in extruder 4 einlegen. Klicken wenn fertig." ++ #define(length = 20, lines = 1) MSG_CHANGE_EXTR "Wechsel extruder" ++ + + ++ #define(length = 20, lines = 4) MSG_FIL_ADJUSTING "Filament positionieren. Bitte warten." ++ #define(length = 20, lines = 8) MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ "Filamente sind jetzt eingestellt. Bitte reinigen Sie die Duese zur Kalibrierung. Klicken wenn fertig." ++ ++ #define(length = 20, lines = 1) MSG_CALIBRATE_E "Kalibriere E" ++//#define(length=20, lines=1) "Reset E Cal." + ++#define(length = 20, lines = 8) MSG_E_CAL_KNOB "Knopf drehen bis die Filamentmarkierung erreicht ist. Klicken wenn fertig." ++ ++//#define(length=20, lines=1) MSG_FARM_CARD_MENU "Farm mode print" + ++#define(length = 20, lines = 8) MSG_MARK_FIL "Filament 100mm vom Extrudergehaeuse markieren. Klicken wenn Fertig." ++ #define(length = 20, lines = 8) MSG_CLEAN_NOZZLE_E "E-Kalibrierung beendet. Bitte reinigen Sie die Duese. Klicken wenn fertig." ++ #define(length = 20, lines = 3) MSG_WAITING_TEMP "Warten auf Abkuehlung von Heater und Bed." + ++ #define(length = 20, lines = 2) MSG_FILAMENT_CLEAN "Ist Farbe rein?" ++ #define(lenght = 20, lines = 1) MSG_UNLOADING_FILAMENT "Filament auswerfen" ++ #define(length = 20, lines = 8) MSG_PAPER "Legen ein Blatt Papier unter die Duese waehrend der Kalibrierung der ersten 4 Punkte. Wenn die Duese das Papier einklemmt, Drucker sofort ausschalten" ++ ++#define MSG_BED_CORRECTION_MENU "Bed level Korrekt" + ++ #define MSG_BED_CORRECTION_LEFT "Links [um]" ++ #define MSG_BED_CORRECTION_RIGHT "Rechts [um]" ++ #define MSG_BED_CORRECTION_FRONT "Vorne [um]" ++ #define MSG_BED_CORRECTION_REAR "Hinten [um]" ++ #define MSG_BED_CORRECTION_RESET "Ruecksetzen" ++ ++#define MSG_MESH_BED_LEVELING "Mesh Bed Leveling" ++ #define MSG_MENU_CALIBRATION "Kalibrierung" + ++ #define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF "SD Karte [normal]" ++ #define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON "SD Karte [FlashAir]" + +#define MSG_FINISHING_MOVEMENTS "Bewegung beenden" +#define MSG_PRINT_PAUSED "Druck pausiert" +#define MSG_RESUMING_PRINT "Druck weitergehen" +#define MSG_PID_EXTRUDER "PID Kalibrierung" +#define MSG_SET_TEMPERATURE "Temp. einsetzen" +#define MSG_PID_FINISHED "PID Kalib. fertig" +#define MSG_PID_RUNNING "PID Kalib." + +#define MSG_CALIBRATE_PINDA "Kalibrieren" +#define MSG_CALIBRATION_PINDA_MENU "Temp. kalibrieren" +#define MSG_PINDA_NOT_CALIBRATED "Temperatur wurde nicht kalibriert" +#define MSG_PINDA_PREHEAT "PINDA erwaermen" +#define MSG_TEMP_CALIBRATION "Temp Kalib. " +#define MSG_TEMP_CALIBRATION_DONE "Temp. Kalibrierung fertig. Klicken um weiter zu gehen." +#define MSG_TEMP_CALIBRATION_ON "Temp. Kal. [ON]" +#define MSG_TEMP_CALIBRATION_OFF "Temp. Kal. [OFF]" + +#define MSG_LOAD_ALL "Alle laden" +#define MSG_LOAD_FILAMENT_1 "Filament 1 laden" +#define MSG_LOAD_FILAMENT_2 "Filament 2 laden" +#define MSG_LOAD_FILAMENT_3 "Filament 3 laden" +#define MSG_LOAD_FILAMENT_4 "Filament 4 laden" +#define MSG_UNLOAD_FILAMENT_1 "Filam. 1 entladen" +#define MSG_UNLOAD_FILAMENT_2 "Filam. 2 entladen" +#define MSG_UNLOAD_FILAMENT_3 "Filam. 3 entladen" +#define MSG_UNLOAD_FILAMENT_4 "Filam. 4 entladen" +#define MSG_UNLOAD_ALL "Alles entladen" +#define MSG_PREPARE_FILAMENT "Filam. bereithalten" +#define MSG_ALL "Alle" +#define MSG_USED "Beim Druck benutzte" +#define MSG_CURRENT "Aktuelles" +#define MSG_CHOOSE_EXTRUDER "Waehlen Sie Extruder" +#define MSG_EXTRUDER "Extruder" +#define MSG_EXTRUDER_1 "Extruder 1" +#define MSG_EXTRUDER_2 "Extruder 2" +#define MSG_EXTRUDER_3 "Extruder 3" +#define MSG_EXTRUDER_4 "Extruder 4" \ No newline at end of file diff --git a/Firmware/language_en.h b/Firmware/language_en.h index f5e881b72..2cc2824e6 100644 --- a/Firmware/language_en.h +++ b/Firmware/language_en.h @@ -69,8 +69,19 @@ #define MSG_SETTINGS "Settings" #define MSG_PREHEAT "Preheat" -#define MSG_UNLOAD_FILAMENT "Unload filament" -#define MSG_LOAD_FILAMENT "Load filament" +#define(length=17) MSG_UNLOAD_FILAMENT "Unload filament" +#define(length=17) MSG_LOAD_FILAMENT "Load filament" +#define(length=17) MSG_LOAD_FILAMENT_1 "Load filament 1" +#define(length=17) MSG_LOAD_FILAMENT_2 "Load filament 2" +#define(length=17) MSG_LOAD_FILAMENT_3 "Load filament 3" +#define(length=17) MSG_LOAD_FILAMENT_4 "Load filament 4" +#define(length=17) MSG_UNLOAD_FILAMENT_1 "Unload filament 1" +#define(length=17) MSG_UNLOAD_FILAMENT_2 "Unload filament 2" +#define(length=17) MSG_UNLOAD_FILAMENT_3 "Unload filament 3" +#define(length=17) MSG_UNLOAD_FILAMENT_4 "Unload filament 4" +#define MSG_UNLOAD_ALL "Unload all" +#define MSG_LOAD_ALL "Load all" + #define MSG_RECTRACT "Rectract" #define MSG_ERROR "ERROR:" @@ -162,9 +173,9 @@ #define MSG_SELFTEST_ENDSTOPS "Endstops" #define MSG_SELFTEST_MOTOR "Motor" #define MSG_SELFTEST_ENDSTOP "Endstop" -#define MSG_SELFTEST_ENDSTOP_NOTHIT "Endstop not hit" +#define(length=20,lines=1) MSG_SELFTEST_ENDSTOP_NOTHIT "Endstop not hit" #define MSG_SELFTEST_OK "Self test OK" -#define MSG_LOOSE_PULLEY "Loose pulley" +#define(length=20,lines=1) MSG_LOOSE_PULLEY "Loose pulley" #define(length=20) MSG_SELFTEST_FAN "Fan test"; #define(length=20) MSG_SELFTEST_COOLING_FAN "Front print fan?"; @@ -192,7 +203,7 @@ #define MSG_HOMEYZ_PROGRESS "Calibrating Z" #define MSG_HOMEYZ_DONE "Calibration done" -#define MSG_SHOW_END_STOPS "Show end stops" +#define(length=17,lines=1) MSG_SHOW_END_STOPS "Show end stops" #define MSG_CALIBRATE_BED "Calibrate XYZ" #define MSG_CALIBRATE_BED_RESET "Reset XYZ calibr." @@ -208,6 +219,7 @@ #define(length=14) MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2 " of 9" #define(length=60) MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1 "Measuring reference height of calibration point" #define(length=14) MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2 " of 9" +#define(length=20) MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION "Iteration " #define(length=20,lines=8) MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND "XYZ calibration failed. Bed calibration point was not found." #define(length=20,lines=8) MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED "XYZ calibration failed. Please consult the manual." @@ -237,8 +249,6 @@ #define(length=20, lines=4) MSG_FILAMENT_LOADING_T3 "Insert filament into extruder 4. Click when done." #define(length=20, lines=1) MSG_CHANGE_EXTR "Change extruder" -#define(length=20, lines=1) MSG_FIL_LOADED_CHECK "Is filament loaded?" -#define(length=20, lines=2) MSG_FIL_TUNING "Rotate the knob to adjust filament." #define(length=20, lines=4) MSG_FIL_ADJUSTING "Adjusting filaments. Please wait." #define(length=20,lines=8) MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ "Filaments are now adjusted. Please clean the nozzle for calibration. Click when done." #define(length=20, lines=4) MSG_STACK_ERROR "Error - static memory has been overwritten" @@ -251,18 +261,45 @@ #define(length=20, lines=8) MSG_CLEAN_NOZZLE_E "E calibration finished. Please clean the nozzle. Click when done." #define(length=20, lines=3) MSG_WAITING_TEMP "Waiting for nozzle and bed cooling" #define(length=20, lines=2) MSG_FILAMENT_CLEAN "Is color clear?" -#define(lenght=20) MSG_UNLOADING_FILAMENT "Unloading filament" +#define(lenght=18, lines=1) MSG_UNLOADING_FILAMENT "Unloading filament" #define(length=20, lines=8) MSG_PAPER "Place a sheet of paper under the nozzle during the calibration of first 4 points. If the nozzle catches the paper, power off the printer immediately." #define MSG_BED_CORRECTION_MENU "Bed level correct" -#define MSG_BED_CORRECTION_LEFT "Left side um" -#define MSG_BED_CORRECTION_RIGHT "Right side um" -#define MSG_BED_CORRECTION_FRONT "Front side um" -#define MSG_BED_CORRECTION_REAR "Rear side um" +#define(length=14,lines=1) MSG_BED_CORRECTION_LEFT "Left side [um]" +#define(length=14,lines=1) MSG_BED_CORRECTION_RIGHT "Right side[um]" +#define(length=14,lines=1) MSG_BED_CORRECTION_FRONT "Front side[um]" +#define(length=14,lines=1) MSG_BED_CORRECTION_REAR "Rear side [um]" #define MSG_BED_CORRECTION_RESET "Reset" #define MSG_MESH_BED_LEVELING "Mesh Bed Leveling" #define MSG_MENU_CALIBRATION "Calibration" -#define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF "SD card [normal]" -#define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON "SD card [FlshAir]" -#define MSG_PRINTER_DISCONNECTED "Printer disconnected" \ No newline at end of file +#define(length=19, lines=1) MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF "SD card [normal]" +#define(length=19, lines=1) MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON "SD card [FlshAir]" +#define(length=20, lines=1) MSG_PRINTER_DISCONNECTED "Printer disconnected" +#define(length=20, lines=1) MSG_FINISHING_MOVEMENTS "Finishing movements" +#define(length=20, lines=1) MSG_PRINT_PAUSED "Print paused" +#define(length=20, lines=1) MSG_RESUMING_PRINT "Resuming print" +#define(length=17, lines=1) MSG_PID_EXTRUDER "PID calibration" +#define(length=19, lines=1) MSG_SET_TEMPERATURE "Set temperature:" +#define(length=20, lines=1) MSG_PID_FINISHED "PID cal. finished" +#define(length=20, lines=1) MSG_PID_RUNNING "PID cal. " + +#define(length=17, lines=1) MSG_CALIBRATE_PINDA "Calibrate" +#define(length=17, lines=1) MSG_CALIBRATION_PINDA_MENU "Temp. calibration" +#define(length=20, lines=4) MSG_PINDA_NOT_CALIBRATED "Temperature calibration has not been run yet" +#define(length=20, lines=1) MSG_PINDA_PREHEAT "PINDA Heating" +#define(length=20, lines=1) MSG_TEMP_CALIBRATION "Temp. cal. " +#define(length=20, lines=4) MSG_TEMP_CALIBRATION_DONE "Temperature calibration is finished. Click to continue." +#define(length=20, lines=1) MSG_TEMP_CALIBRATION_ON "Temp. cal. [ON]" +#define(length=20, lines=1) MSG_TEMP_CALIBRATION_OFF "Temp. cal. [OFF]" +#define(length=20, lines=1) MSG_PREPARE_FILAMENT "Prepare new filament" +#define(length=19, lines=1) MSG_ALL "All" +#define(length=19, lines=1) MSG_USED "Used during print" +#define(length=19, lines=1) MSG_CURRENT "Current" +#define(length=20, lines=1) MSG_CHOOSE_EXTRUDER "Choose extruder:" +#define(length=17, lines=1) MSG_EXTRUDER "Extruder" +#define(length=17, lines=1) MSG_EXTRUDER_1 "Extruder 1" +#define(length=17, lines=1) MSG_EXTRUDER_2 "Extruder 2" +#define(length=17, lines=1) MSG_EXTRUDER_3 "Extruder 3" +#define(length=17, lines=1) MSG_EXTRUDER_4 "Extruder 4" + diff --git a/Firmware/language_es.h b/Firmware/language_es.h index cb1e9563e..d44cda831 100644 --- a/Firmware/language_es.h +++ b/Firmware/language_es.h @@ -206,6 +206,7 @@ #define MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1 "Medir la altura del punto de la calibracion" #define MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2 " de 9" +#define MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION "Reiteracion " #define MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND "Calibracion XYZ fallada. Puntos de calibracion en la cama no encontrados." #define MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED "Calibracion XYZ fallada. Consultar el manual por favor." #define MSG_BED_SKEW_OFFSET_DETECTION_PERFECT "Calibracion XYZ ok. Ejes X/Y perpendiculares. Felicitaciones!" @@ -242,8 +243,7 @@ #define MSG_FILAMENT_LOADING_T2 "Insertar filamento en el extrusor 3. Haga clic una vez terminado." #define MSG_FILAMENT_LOADING_T3 "Insertar filamento en el extrusor 4. Haga clic una vez terminado." #define MSG_CHANGE_EXTR "Cambiar extrusor." -#define MSG_FIL_LOADED_CHECK "Esta cargado el filamento?" -#define MSG_FIL_TUNING "Rotar el mando para ajustar el filamento." + #define MSG_FIL_ADJUSTING "Ajustando filamentos. Esperar por favor." #define MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ "Filamentos ajustados. Limpie la boquilla para calibracion. Haga clic una vez terminado." #define MSG_CALIBRATE_E "Calibrar E" @@ -253,4 +253,46 @@ #define MSG_WAITING_TEMP "Esperando enfriamiento de la cama y del extrusor." #define MSG_FILAMENT_CLEAN "Es el nuevo color nitido?" #define MSG_UNLOADING_FILAMENT "Soltando filamento" -#define MSG_PAPER "Colocar una hoja de papel sobre la superficie de impresion durante la calibracion de los primeros 4 puntos. Si la boquilla mueve el papel, apagar impresora inmediatamente." \ No newline at end of file +#define MSG_PAPER "Colocar una hoja de papel sobre la superficie de impresion durante la calibracion de los primeros 4 puntos. Si la boquilla mueve el papel, apagar impresora inmediatamente." + +#define MSG_FINISHING_MOVEMENTS "Term. movimientos" +#define MSG_PRINT_PAUSED "Impresion en pausa" +#define MSG_RESUMING_PRINT "Reanudar impresion" +#define MSG_PID_EXTRUDER "Calibracion PID" +#define MSG_SET_TEMPERATURE "Establecer temp.:" +#define MSG_PID_FINISHED "Cal. PID terminada" +#define MSG_PID_RUNNING "Cal. PID " + +#define MSG_CALIBRATE_PINDA "Calibrar" +#define MSG_CALIBRATION_PINDA_MENU "Calibracion temp." +#define MSG_PINDA_NOT_CALIBRATED "La temperatura de calibracion no ha sido ajustada" +#define MSG_PINDA_PREHEAT "Calentando PINDA" +#define MSG_TEMP_CALIBRATION "Cal. temp. " +#define MSG_TEMP_CALIBRATION_DONE "Calibracon temperatura terminada. Presionar para continuar." +#define MSG_TEMP_CALIBRATION_ON "Cal. temp. [ON]" +#define MSG_TEMP_CALIBRATION_OFF "Cal. temp. [OFF]" + +#define MSG_PREPARE_FILAMENT "Preparar filamento" + + + +#define MSG_LOAD_ALL "Intr. todos fil." +#define MSG_LOAD_FILAMENT_1 "Introducir fil. 1" +#define MSG_LOAD_FILAMENT_2 "Introducir fil. 2" +#define MSG_LOAD_FILAMENT_3 "Introducir fil. 3" +#define MSG_LOAD_FILAMENT_4 "Introducir fil. 4" +#define MSG_UNLOAD_FILAMENT_1 "Soltar fil. 1" +#define MSG_UNLOAD_FILAMENT_2 "Soltar fil. 2" +#define MSG_UNLOAD_FILAMENT_3 "Soltar fil. 3" +#define MSG_UNLOAD_FILAMENT_4 "Soltar fil. 4" +#define MSG_UNLOAD_ALL "Soltar todos fil." +#define MSG_PREPARE_FILAMENT "Preparar filamento" +#define MSG_ALL "Todos" +#define MSG_USED "Usado en impresion" +#define MSG_CURRENT "Actual" +#define MSG_CHOOSE_EXTRUDER "Elegir extrusor:" +#define MSG_EXTRUDER "Extrusor" +#define MSG_EXTRUDER_1 "Extrusor 1" +#define MSG_EXTRUDER_2 "Extrusor 2" +#define MSG_EXTRUDER_3 "Extrusor 3" +#define MSG_EXTRUDER_4 "Extrusor 4" \ No newline at end of file diff --git a/Firmware/language_it.h b/Firmware/language_it.h index dc9e2a3a2..629754760 100644 --- a/Firmware/language_it.h +++ b/Firmware/language_it.h @@ -1,251 +1,289 @@ -#define WELCOME_MSG CUSTOM_MENDEL_NAME " pronta." -#define MSG_SD_INSERTED "SD inserita" -#define MSG_SD_REMOVED "SD rimossa" -#define MSG_MAIN "Menu principale" -#define MSG_DISABLE_STEPPERS "Disabilit motori" -#define MSG_AUTO_HOME "Trova origine" -#define MSG_SET_HOME_OFFSETS "Set home offsets" -#define MSG_SET_ORIGIN "Set origin" -#define MSG_COOLDOWN "Raffredda" -#define MSG_SWITCH_PS_ON "Switch power on" -#define MSG_SWITCH_PS_OFF "Switch power off" -#define MSG_MOVE_AXIS "Muovi asse" -#define MSG_MOVE_X "Muovi X" -#define MSG_MOVE_Y "Muovi Y" -#define MSG_MOVE_Z "Muovi Z" -#define MSG_MOVE_E "Muovi Estrusore" -#define MSG_MOVE_01MM "Move 0.1mm" -#define MSG_MOVE_1MM "Move 1mm" -#define MSG_MOVE_10MM "Move 10mm" -#define MSG_SPEED "Velocita" -#define MSG_NOZZLE "Ugello" -#define MSG_NOZZLE1 "Nozzle2" -#define MSG_NOZZLE2 "Nozzle3" -#define MSG_BED "Letto" -#define MSG_FAN_SPEED "Velocita vent." -#define MSG_FLOW "Flusso" -#define MSG_TEMPERATURE "Temperatura" -#define MSG_MOTION "Motion" -#define MSG_VOLUMETRIC "Filament" -#define MSG_VOLUMETRIC_ENABLED "E in mm3" -#define MSG_STORE_EPROM "Store memory" -#define MSG_LOAD_EPROM "Load memory" -#define MSG_RESTORE_FAILSAFE "Restore failsafe" -#define MSG_REFRESH "\xF8" "Refresh" -#define MSG_WATCH "Schermata info" -#define MSG_TUNE "Regola" -#define MSG_PAUSE_PRINT "Metti in pausa" -#define MSG_RESUME_PRINT "Riprendi stampa" -#define MSG_STOP_PRINT "Arresta stampa" -#define MSG_CARD_MENU "Stampa da SD" -#define MSG_NO_CARD "Nessuna SD" -#define MSG_DWELL "Sospensione..." -#define MSG_USERWAIT "Attendendo utente" -#define MSG_RESUMING "Riprendi stampa" -#define MSG_PRINT_ABORTED "Stampa abortita" -#define MSG_NO_MOVE "Nessun movimento." -#define MSG_KILLED "IN TILT." -#define MSG_STOPPED "ARRESTATO." -#define MSG_FILAMENTCHANGE "Camb. filamento" -#define MSG_INIT_SDCARD "Init. SD card" -#define MSG_CNG_SDCARD "Change SD card" -#define MSG_ZPROBE_OUT "Z probe out. bed" -#define MSG_POSITION_UNKNOWN "Home X/Y before Z" -#define MSG_ZPROBE_ZOFFSET "Z Offset" -#define MSG_BABYSTEP_X "Babystep X" -#define MSG_BABYSTEP_Y "Babystep Y" -#define MSG_BABYSTEP_Z "Compensazione Z" -#define MSG_ADJUSTZ "Autoregolare Z?" -#define MSG_PICK_Z "Pick print" - -#define MSG_SETTINGS "Impostazioni" -#define MSG_PREHEAT "Preriscalda" -#define MSG_HEATING "Riscaldamento..." -#define MSG_SUPPORT "Support" -#define MSG_YES "Si" -#define MSG_NO "No" -#define MSG_NOT_LOADED "Fil. non caricato" -#define MSG_NOT_COLOR "Colore non puro" -#define MSG_LOADING_COLOR "Caricando colore" -#define MSG_CHANGE_SUCCESS "Cambio riuscito!" -#define MSG_PRESS "e cliccare manopola" -#define MSG_INSERT_FILAMENT "Inserire filamento" -#define MSG_CHANGING_FILAMENT "Cambiando filam." - -#define MSG_PLEASE_WAIT "Aspetta" -#define MSG_PREHEAT_NOZZLE "Preris. ugello!" -#define MSG_HEATING_COMPLETE "Riscald. completo" -#define MSG_BED_HEATING "Riscald. letto" -#define MSG_BED_DONE "Piatto fatto." -#define MSG_ERROR "ERRORE:" -#define MSG_CORRECTLY "Cambiato corr.?" -#define MSG_LOADING_FILAMENT "Caricando filam." -#define MSG_UNLOAD_FILAMENT "Scarica filamento" -#define MSG_LOAD_FILAMENT "Carica filamento" - -#define MSG_SILENT_MODE_ON "Modo [silenzioso]" -#define MSG_SILENT_MODE_OFF "Mode [forte]" -#define MSG_REBOOT "Riavvia stampante" -#define MSG_TAKE_EFFECT " per attualizzare" - -#define MSG_Enqueing "enqueing \"" -#define MSG_POWERUP "PowerUp" -#define MSG_CONFIGURATION_VER " Last Updated: " -#define MSG_FREE_MEMORY " Free Memory: " -#define MSG_PLANNER_BUFFER_BYTES " PlannerBufferBytes: " -#define MSG_OK "ok" -#define MSG_ERR_CHECKSUM_MISMATCH "checksum mismatch, Last Line: " -#define MSG_ERR_NO_CHECKSUM "No Checksum with line number, Last Line: " -#define MSG_BEGIN_FILE_LIST "Begin file list" -#define MSG_END_FILE_LIST "End file list" -#define MSG_M104_INVALID_EXTRUDER "M104 Invalid extruder " -#define MSG_M105_INVALID_EXTRUDER "M105 Invalid extruder " -#define MSG_M200_INVALID_EXTRUDER "M200 Invalid extruder " -#define MSG_M218_INVALID_EXTRUDER "M218 Invalid extruder " -#define MSG_M221_INVALID_EXTRUDER "M221 Invalid extruder " -#define MSG_ERR_NO_THERMISTORS "No thermistors - no temperature" -#define MSG_M109_INVALID_EXTRUDER "M109 Invalid extruder " -#define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1.0.2; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" CUSTOM_MENDEL_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID "\n" -#define MSG_ERR_KILLED "Printer halted. kill() called!" -#define MSG_ERR_STOPPED "Printer stopped due to errors. Fix the error and use M999 to restart. (Temperature is reset. Set it after restarting)" -#define MSG_RESEND "Resend: " -#define MSG_M119_REPORT "Reporting endstop status" -#define MSG_ENDSTOP_HIT "TRIGGERED" -#define MSG_ENDSTOP_OPEN "open" -#define MSG_SD_CANT_OPEN_SUBDIR "Cannot open subdir" -#define MSG_SD_INIT_FAIL "SD init fail" -#define MSG_SD_VOL_INIT_FAIL "volume.init failed" -#define MSG_SD_OPENROOT_FAIL "openRoot failed" -#define MSG_SD_CARD_OK "SD card ok" -#define MSG_SD_WORKDIR_FAIL "workDir open failed" -#define MSG_SD_OPEN_FILE_FAIL "open failed, File: " -#define MSG_SD_FILE_OPENED "File opened: " -#define MSG_SD_FILE_SELECTED "File selected" -#define MSG_SD_WRITE_TO_FILE "Writing to file: " -#define MSG_SD_PRINTING_BYTE "SD printing byte " -#define MSG_SD_NOT_PRINTING "Not SD printing" -#define MSG_SD_ERR_WRITE_TO_FILE "error writing to file" -#define MSG_SD_CANT_ENTER_SUBDIR "Cannot enter subdir: " -#define MSG_STEPPER_TOO_HIGH "Steprate too high: " -#define MSG_ENDSTOPS_HIT "endstops hit: " -#define MSG_ERR_COLD_EXTRUDE_STOP " cold extrusion prevented" -#define MSG_BABYSTEPPING_X "Babystepping X" -#define MSG_BABYSTEPPING_Y "Babystepping Y" -#define MSG_BABYSTEPPING_Z "Adjusting Z" -#define MSG_SERIAL_ERROR_MENU_STRUCTURE "Error in menu structure" - -#define MSG_LANGUAGE_NAME "Italiano" -#define MSG_LANGUAGE_SELECT "Seleziona lingua" -#define MSG_PRUSA3D "prusa3d.com" -#define MSG_PRUSA3D_FORUM "forum.prusa3d.com" -#define MSG_PRUSA3D_HOWTO "howto.prusa3d.com" - -#define MSG_SELFTEST_ERROR "Autotest negativo" -#define MSG_SELFTEST_PLEASECHECK "Verificare:" -#define MSG_SELFTEST_NOTCONNECTED "Non connesso" -#define MSG_SELFTEST_HEATERTHERMISTOR "Riscald./Termist." -#define MSG_SELFTEST_BEDHEATER "Letto/Riscald." -#define MSG_SELFTEST_WIRINGERROR "Errore cablaggio" -#define MSG_SELFTEST_ENDSTOPS "Finecorsa (2)" -#define MSG_SELFTEST_MOTOR "Motore" -#define MSG_SELFTEST_ENDSTOP "Finecorsa" -#define MSG_SELFTEST_ENDSTOP_NOTHIT "Finec. fuori por." -#define MSG_SELFTEST_OK "Autotest OK" - -#define(length=20) MSG_SELFTEST_FAN "Prova del ventilator"; -#define(length=20) MSG_SELFTEST_COOLING_FAN "Vent di stampa ant.?"; -#define(length=20) MSG_SELFTEST_EXTRUDER_FAN "Vent SX sull'ugello?"; -#define MSG_SELFTEST_FAN_YES "Gira"; -#define MSG_SELFTEST_FAN_NO "Non si gira"; - -#define MSG_STATS_TOTALFILAMENT "Filamento tot:" -#define MSG_STATS_TOTALPRINTTIME "Tempo stampa tot:" -#define MSG_STATS_FILAMENTUSED "Filamento usato:" -#define MSG_STATS_PRINTTIME "Tempo di stampa:" -#define MSG_SELFTEST_START "Avvia autotest" -#define MSG_SELFTEST_CHECK_ENDSTOPS "Verifica finecorsa" -#define MSG_SELFTEST_CHECK_HOTEND "Verifica ugello" -#define MSG_SELFTEST_CHECK_X "Verifica asse X" -#define MSG_SELFTEST_CHECK_Y "Verifica asse Y" -#define MSG_SELFTEST_CHECK_Z "Verifica asse Z" -#define MSG_SELFTEST_CHECK_BED "Verifica letto" -#define MSG_SELFTEST_CHECK_ALLCORRECT "Nessun errore" -#define MSG_SELFTEST "Autotest" -#define MSG_SELFTEST_FAILED "Autotest fallito" -#define MSG_STATISTICS "Statistiche" -#define MSG_USB_PRINTING "Stampa da USB" -#define MSG_HOMEYZ "Calibra Z" -#define MSG_HOMEYZ_PROGRESS "Calibrando Z" -#define MSG_HOMEYZ_DONE "Calibrazione OK" - - - -#define MSG_SHOW_END_STOPS "Stato finecorsa" -#define MSG_CALIBRATE_BED "Calibra XYZ" -#define MSG_CALIBRATE_BED_RESET "Reset XYZ calibr." - -#define MSG_MOVE_CARRIAGE_TO_THE_TOP "Calibrazione XYZ. Ruotare la manopola per alzare il carrello Z fino all'altezza massima. Click per terminare." -#define MSG_MOVE_CARRIAGE_TO_THE_TOP_Z "Calibrazione Z. Ruotare la manopola per alzare il carrello Z fino all'altezza massima. Click per terminare." - -#define MSG_CONFIRM_NOZZLE_CLEAN "Pulire l'ugello per la calibrazione, poi fare click." -#define MSG_CONFIRM_CARRIAGE_AT_THE_TOP "I carrelli Z sin/des sono altezza max?" - -#define MSG_FIND_BED_OFFSET_AND_SKEW_LINE1 "Ricerca del letto punto di calibraz." -#define MSG_FIND_BED_OFFSET_AND_SKEW_LINE2 " su 4" -#define MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1 "Perfezion. il letto punto di calibraz." -#define MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2 " su 9" -#define MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1 "Misurare l'altezza di riferimento del punto di calibrazione" -#define MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2 " su 9" - -#define MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND "Calibrazione XYZ fallita. Il punto di calibrazione sul letto non e' stato trovato." -#define MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED "Calibrazione XYZ fallita. Si prega di consultare il manuale." -#define MSG_BED_SKEW_OFFSET_DETECTION_PERFECT "Calibrazione XYZ OK. Gli assi X/Y sono perpendicolari. Complimenti!" -#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD "Calibrazion XYZ corretta. Assi X/Y leggermente storti. Ben fatto!" -#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME "Calibrazion XYZ corretta. La distorsione verra' automaticamente compensata." -#define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR "Calibrazione XYZ fallita. Punto anteriore sinistro non raggiungibile." -#define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR "Calibrazione XYZ fallita. Punto anteriore destro non raggiungibile." -#define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR "Calibrazione XYZ fallita. Punti anteriori non raggiungibili." -#define MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR "Calibrazione XYZ compromessa. Punto anteriore sinistro non raggiungibile." -#define MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR "Calibrazione XYZ compromessa. Punto anteriore destro non raggiungibile." -#define MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR "Calibrazione XYZ compromessa. Punti anteriori non raggiungibili." - -#define MSG_BED_LEVELING_FAILED_POINT_LOW "Livellamento letto fallito.NoRispSensor Residui su ugello? In attesa di reset." -#define MSG_BED_LEVELING_FAILED_POINT_HIGH "Livellamento letto fallito.Risp sensore troppo prestoIn attesa di reset." -#define MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED "Livellamento letto fallito. Sensore discon. o Cavo Dann. In attesa di reset." - -#define MSG_NEW_FIRMWARE_AVAILABLE "Nuova versione del firmware disponibile" -#define MSG_NEW_FIRMWARE_PLEASE_UPGRADE "Prega aggiorna." - -#define MSG_FOLLOW_CALIBRATION_FLOW "Stampante ancora non calibrata. Si prega di seguire il manuale, capitolo PRIMI PASSI, sezione della calibrazione." -#define MSG_BABYSTEP_Z_NOT_SET "Distanza tra la punta dell'ugello e la superficie del letto non ancora imposta. Si prega di seguire il manuale, capitolo First steps, sezione First layer calibration." - -#define MSG_BED_CORRECTION_MENU "Correz. liv.letto" -#define MSG_BED_CORRECTION_LEFT "Lato sinistro" -#define MSG_BED_CORRECTION_RIGHT "Lato destro" -#define MSG_BED_CORRECTION_FRONT "Lato ateriore" -#define MSG_BED_CORRECTION_REAR "Lato posteriore" -#define MSG_BED_CORRECTION_RESET "Reset" - -#define MSG_MESH_BED_LEVELING "Mesh livel. letto" -#define MSG_MENU_CALIBRATION "Calibrazione" -#define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF "SD card [normal]" -#define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON "SD card [FlshAir]" - -#define MSG_LOOSE_PULLEY "Puleggia lenta" -#define MSG_FILAMENT_LOADING_T0 "Inserire filamento nell'estrusore 1. Click per continuare." -#define MSG_FILAMENT_LOADING_T1 "Inserire filamento nell'estrusore 2. Click per continuare." -#define MSG_FILAMENT_LOADING_T2 "Inserire filamento nell'estrusore 3. Click per continuare." -#define MSG_FILAMENT_LOADING_T3 "Inserire filamento nell'estrusore 4. Click per continuare." -#define MSG_CHANGE_EXTR "Cambio estrusore." -#define MSG_FIL_LOADED_CHECK "Filamento caricato?" -#define MSG_FIL_TUNING "Girare la manopola per regolare il filamento" -#define MSG_FIL_ADJUSTING "Filamento in fase di regolazione. Attendere prego." -#define MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ "I filamenti sono regolati. Si prega di pulire l'ugello per la calibrazione. Click per continuare." -#define MSG_CALIBRATE_E "Calibra E" -#define MSG_E_CAL_KNOB "Girare la manopola affinche' il segno raggiunga il corpo dell'estrusore. Click per continuare." -#define MSG_MARK_FIL "Segnare il filamento a 100 mm di distanza dal corpo dell'estrusore. Click per continuare." -#define MSG_CLEAN_NOZZLE_E "Calibrazione E terminata. Si prega di pulire l'ugello. Click per continuare." -#define MSG_WAITING_TEMP "In attesa del raffreddamento della testina e del piatto" -#define MSG_FILAMENT_CLEAN "Il colore e' nitido?" -#define MSG_UNLOADING_FILAMENT "Rilasc. filamento" -#define MSG_PAPER "Porre un foglio sotto l'ugello durante la calibrazione dei primi 4 punti. In caso l'ugello muova il foglio spegnere prontamente la stampante." \ No newline at end of file +#define WELCOME_MSG CUSTOM_MENDEL_NAME " pronta." +#define MSG_SD_INSERTED "SD inserita" +#define MSG_SD_REMOVED "SD rimossa" +#define MSG_MAIN "Menu principale" +#define MSG_DISABLE_STEPPERS "Disabilit motori" +#define MSG_AUTO_HOME "Trova origine" +#define MSG_SET_HOME_OFFSETS "Set home offsets" +#define MSG_SET_ORIGIN "Set origin" +#define MSG_COOLDOWN "Raffredda" +#define MSG_SWITCH_PS_ON "Switch power on" +#define MSG_SWITCH_PS_OFF "Switch power off" +#define MSG_MOVE_AXIS "Muovi asse" +#define MSG_MOVE_X "Muovi X" +#define MSG_MOVE_Y "Muovi Y" +#define MSG_MOVE_Z "Muovi Z" +#define MSG_MOVE_E "Muovi Estrusore" +#define MSG_MOVE_01MM "Move 0.1mm" +#define MSG_MOVE_1MM "Move 1mm" +#define MSG_MOVE_10MM "Move 10mm" +#define MSG_SPEED "Velocita" +#define MSG_NOZZLE "Ugello" +#define MSG_NOZZLE1 "Nozzle2" +#define MSG_NOZZLE2 "Nozzle3" +#define MSG_BED "Letto" +#define MSG_FAN_SPEED "Velocita vent." +#define MSG_FLOW "Flusso" +#define MSG_TEMPERATURE "Temperatura" +#define MSG_MOTION "Motion" +#define MSG_VOLUMETRIC "Filament" +#define MSG_VOLUMETRIC_ENABLED "E in mm3" +#define MSG_STORE_EPROM "Store memory" +#define MSG_LOAD_EPROM "Load memory" +#define MSG_RESTORE_FAILSAFE "Restore failsafe" +#define MSG_REFRESH "\xF8" "Refresh" +#define MSG_WATCH "Schermata info" +#define MSG_TUNE "Regola" +#define MSG_PAUSE_PRINT "Metti in pausa" +#define MSG_RESUME_PRINT "Riprendi stampa" +#define MSG_STOP_PRINT "Arresta stampa" +#define MSG_CARD_MENU "Stampa da SD" +#define MSG_NO_CARD "Nessuna SD" +#define MSG_DWELL "Sospensione..." +#define MSG_USERWAIT "Attendendo utente" +#define MSG_RESUMING "Riprendi stampa" +#define MSG_PRINT_ABORTED "Stampa abortita" +#define MSG_NO_MOVE "Nessun movimento." +#define MSG_KILLED "IN TILT." +#define MSG_STOPPED "ARRESTATO." +#define MSG_FILAMENTCHANGE "Camb. filamento" +#define MSG_INIT_SDCARD "Init. SD card" +#define MSG_CNG_SDCARD "Change SD card" +#define MSG_ZPROBE_OUT "Z probe out. bed" +#define MSG_POSITION_UNKNOWN "Home X/Y before Z" +#define MSG_ZPROBE_ZOFFSET "Z Offset" +#define MSG_BABYSTEP_X "Babystep X" +#define MSG_BABYSTEP_Y "Babystep Y" +#define MSG_BABYSTEP_Z "Compensazione Z" +#define MSG_ADJUSTZ "Autoregolare Z?" +#define MSG_PICK_Z "Pick print" + +#define MSG_SETTINGS "Impostazioni" +#define MSG_PREHEAT "Preriscalda" +#define MSG_HEATING "Riscaldamento..." +#define MSG_SUPPORT "Support" +#define MSG_YES "Si" +#define MSG_NO "No" +#define MSG_NOT_LOADED "Fil. non caricato" +#define MSG_NOT_COLOR "Colore non puro" +#define MSG_LOADING_COLOR "Caricando colore" +#define MSG_CHANGE_SUCCESS "Cambio riuscito!" +#define MSG_PRESS "e cliccare manopola" +#define MSG_INSERT_FILAMENT "Inserire filamento" +#define MSG_CHANGING_FILAMENT "Cambiando filam." + +#define MSG_PLEASE_WAIT "Aspetta" +#define MSG_PREHEAT_NOZZLE "Preris. ugello!" +#define MSG_HEATING_COMPLETE "Riscald. completo" +#define MSG_BED_HEATING "Riscald. letto" +#define MSG_BED_DONE "Piatto fatto." +#define MSG_ERROR "ERRORE:" +#define MSG_CORRECTLY "Cambiato corr.?" +#define MSG_LOADING_FILAMENT "Caricando filam." +#define MSG_UNLOAD_FILAMENT "Scarica filamento" +#define MSG_LOAD_FILAMENT "Carica filamento" + +#define MSG_SILENT_MODE_ON "Modo [silenzioso]" +#define MSG_SILENT_MODE_OFF "Mode [forte]" +#define MSG_REBOOT "Riavvia stampante" +#define MSG_TAKE_EFFECT " per attualizzare" + +#define MSG_Enqueing "enqueing \"" +#define MSG_POWERUP "PowerUp" +#define MSG_CONFIGURATION_VER " Last Updated: " +#define MSG_FREE_MEMORY " Free Memory: " +#define MSG_PLANNER_BUFFER_BYTES " PlannerBufferBytes: " +#define MSG_OK "ok" +#define MSG_ERR_CHECKSUM_MISMATCH "checksum mismatch, Last Line: " +#define MSG_ERR_NO_CHECKSUM "No Checksum with line number, Last Line: " +#define MSG_BEGIN_FILE_LIST "Begin file list" +#define MSG_END_FILE_LIST "End file list" +#define MSG_M104_INVALID_EXTRUDER "M104 Invalid extruder " +#define MSG_M105_INVALID_EXTRUDER "M105 Invalid extruder " +#define MSG_M200_INVALID_EXTRUDER "M200 Invalid extruder " +#define MSG_M218_INVALID_EXTRUDER "M218 Invalid extruder " +#define MSG_M221_INVALID_EXTRUDER "M221 Invalid extruder " +#define MSG_ERR_NO_THERMISTORS "No thermistors - no temperature" +#define MSG_M109_INVALID_EXTRUDER "M109 Invalid extruder " +#define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1.0.2; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" CUSTOM_MENDEL_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID "\n" +#define MSG_ERR_KILLED "Printer halted. kill() called!" +#define MSG_ERR_STOPPED "Printer stopped due to errors. Fix the error and use M999 to restart. (Temperature is reset. Set it after restarting)" +#define MSG_RESEND "Resend: " +#define MSG_M119_REPORT "Reporting endstop status" +#define MSG_ENDSTOP_HIT "TRIGGERED" +#define MSG_ENDSTOP_OPEN "open" +#define MSG_SD_CANT_OPEN_SUBDIR "Cannot open subdir" +#define MSG_SD_INIT_FAIL "SD init fail" +#define MSG_SD_VOL_INIT_FAIL "volume.init failed" +#define MSG_SD_OPENROOT_FAIL "openRoot failed" +#define MSG_SD_CARD_OK "SD card ok" +#define MSG_SD_WORKDIR_FAIL "workDir open failed" +#define MSG_SD_OPEN_FILE_FAIL "open failed, File: " +#define MSG_SD_FILE_OPENED "File opened: " +#define MSG_SD_FILE_SELECTED "File selected" +#define MSG_SD_WRITE_TO_FILE "Writing to file: " +#define MSG_SD_PRINTING_BYTE "SD printing byte " +#define MSG_SD_NOT_PRINTING "Not SD printing" +#define MSG_SD_ERR_WRITE_TO_FILE "error writing to file" +#define MSG_SD_CANT_ENTER_SUBDIR "Cannot enter subdir: " +#define MSG_STEPPER_TOO_HIGH "Steprate too high: " +#define MSG_ENDSTOPS_HIT "endstops hit: " +#define MSG_ERR_COLD_EXTRUDE_STOP " cold extrusion prevented" +#define MSG_BABYSTEPPING_X "Babystepping X" +#define MSG_BABYSTEPPING_Y "Babystepping Y" +#define MSG_BABYSTEPPING_Z "Adjusting Z" +#define MSG_SERIAL_ERROR_MENU_STRUCTURE "Error in menu structure" + +#define MSG_LANGUAGE_NAME "Italiano" +#define MSG_LANGUAGE_SELECT "Seleziona lingua" +#define MSG_PRUSA3D "prusa3d.com" +#define MSG_PRUSA3D_FORUM "forum.prusa3d.com" +#define MSG_PRUSA3D_HOWTO "howto.prusa3d.com" + +#define MSG_SELFTEST_ERROR "Autotest negativo" +#define MSG_SELFTEST_PLEASECHECK "Verificare:" +#define MSG_SELFTEST_NOTCONNECTED "Non connesso" +#define MSG_SELFTEST_HEATERTHERMISTOR "Riscald./Termist." +#define MSG_SELFTEST_BEDHEATER "Letto/Riscald." +#define MSG_SELFTEST_WIRINGERROR "Errore cablaggio" +#define MSG_SELFTEST_ENDSTOPS "Finecorsa (2)" +#define MSG_SELFTEST_MOTOR "Motore" +#define MSG_SELFTEST_ENDSTOP "Finecorsa" +#define MSG_SELFTEST_ENDSTOP_NOTHIT "Finec. fuori por." +#define MSG_SELFTEST_OK "Autotest OK" + +#define(length=20) MSG_SELFTEST_FAN "Prova del ventilator"; +#define(length=20) MSG_SELFTEST_COOLING_FAN "Vent di stampa ant.?"; +#define(length=20) MSG_SELFTEST_EXTRUDER_FAN "Vent SX sull'ugello?"; +#define MSG_SELFTEST_FAN_YES "Gira"; +#define MSG_SELFTEST_FAN_NO "Non si gira"; + +#define MSG_STATS_TOTALFILAMENT "Filamento tot:" +#define MSG_STATS_TOTALPRINTTIME "Tempo stampa tot:" +#define MSG_STATS_FILAMENTUSED "Filamento usato:" +#define MSG_STATS_PRINTTIME "Tempo di stampa:" +#define MSG_SELFTEST_START "Avvia autotest" +#define MSG_SELFTEST_CHECK_ENDSTOPS "Verifica finecorsa" +#define MSG_SELFTEST_CHECK_HOTEND "Verifica ugello" +#define MSG_SELFTEST_CHECK_X "Verifica asse X" +#define MSG_SELFTEST_CHECK_Y "Verifica asse Y" +#define MSG_SELFTEST_CHECK_Z "Verifica asse Z" +#define MSG_SELFTEST_CHECK_BED "Verifica letto" +#define MSG_SELFTEST_CHECK_ALLCORRECT "Nessun errore" +#define MSG_SELFTEST "Autotest" +#define MSG_SELFTEST_FAILED "Autotest fallito" +#define MSG_STATISTICS "Statistiche" +#define MSG_USB_PRINTING "Stampa da USB" +#define MSG_HOMEYZ "Calibra Z" +#define MSG_HOMEYZ_PROGRESS "Calibrando Z" +#define MSG_HOMEYZ_DONE "Calibrazione OK" + + + +#define MSG_SHOW_END_STOPS "Stato finecorsa" +#define MSG_CALIBRATE_BED "Calibra XYZ" +#define MSG_CALIBRATE_BED_RESET "Reset XYZ calibr." + +#define MSG_MOVE_CARRIAGE_TO_THE_TOP "Calibrazione XYZ. Ruotare la manopola per alzare il carrello Z fino all'altezza massima. Click per terminare." +#define MSG_MOVE_CARRIAGE_TO_THE_TOP_Z "Calibrazione Z. Ruotare la manopola per alzare il carrello Z fino all'altezza massima. Click per terminare." + +#define MSG_CONFIRM_NOZZLE_CLEAN "Pulire l'ugello per la calibrazione, poi fare click." +#define MSG_CONFIRM_CARRIAGE_AT_THE_TOP "I carrelli Z sin/des sono altezza max?" + +#define MSG_FIND_BED_OFFSET_AND_SKEW_LINE1 "Ricerca del letto punto di calibraz." +#define MSG_FIND_BED_OFFSET_AND_SKEW_LINE2 " su 4" +#define MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1 "Perfezion. il letto punto di calibraz." +#define MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2 " su 9" +#define MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1 "Misurare l'altezza di riferimento del punto di calibrazione" +#define MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2 " su 9" +#define MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION "Reiterazione " + +#define MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND "Calibrazione XYZ fallita. Il punto di calibrazione sul letto non e' stato trovato." +#define MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED "Calibrazione XYZ fallita. Si prega di consultare il manuale." +#define MSG_BED_SKEW_OFFSET_DETECTION_PERFECT "Calibrazione XYZ OK. Gli assi X/Y sono perpendicolari. Complimenti!" +#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD "Calibrazion XYZ corretta. Assi X/Y leggermente storti. Ben fatto!" +#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME "Calibrazion XYZ corretta. La distorsione verra' automaticamente compensata." +#define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR "Calibrazione XYZ fallita. Punto anteriore sinistro non raggiungibile." +#define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR "Calibrazione XYZ fallita. Punto anteriore destro non raggiungibile." +#define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR "Calibrazione XYZ fallita. Punti anteriori non raggiungibili." +#define MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR "Calibrazione XYZ compromessa. Punto anteriore sinistro non raggiungibile." +#define MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR "Calibrazione XYZ compromessa. Punto anteriore destro non raggiungibile." +#define MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR "Calibrazione XYZ compromessa. Punti anteriori non raggiungibili." + +#define MSG_BED_LEVELING_FAILED_POINT_LOW "Livellamento letto fallito.NoRispSensor Residui su ugello? In attesa di reset." +#define MSG_BED_LEVELING_FAILED_POINT_HIGH "Livellamento letto fallito.Risp sensore troppo prestoIn attesa di reset." +#define MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED "Livellamento letto fallito. Sensore discon. o Cavo Dann. In attesa di reset." + +#define MSG_NEW_FIRMWARE_AVAILABLE "Nuova versione del firmware disponibile" +#define MSG_NEW_FIRMWARE_PLEASE_UPGRADE "Prega aggiorna." + +#define MSG_FOLLOW_CALIBRATION_FLOW "Stampante ancora non calibrata. Si prega di seguire il manuale, capitolo PRIMI PASSI, sezione della calibrazione." +#define MSG_BABYSTEP_Z_NOT_SET "Distanza tra la punta dell'ugello e la superficie del letto non ancora imposta. Si prega di seguire il manuale, capitolo First steps, sezione First layer calibration." + +#define MSG_BED_CORRECTION_MENU "Correz. liv.letto" +#define MSG_BED_CORRECTION_LEFT "Sinistra [um]" +#define MSG_BED_CORRECTION_RIGHT "Destra [um]" +#define MSG_BED_CORRECTION_FRONT "Fronte [um]" +#define MSG_BED_CORRECTION_REAR "Retro [um]" +#define MSG_BED_CORRECTION_RESET "Reset" + +#define MSG_MESH_BED_LEVELING "Mesh livel. letto" +#define MSG_MENU_CALIBRATION "Calibrazione" +#define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF "SD card [normal]" +#define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON "SD card [FlshAir]" + +#define MSG_LOOSE_PULLEY "Puleggia lenta" +#define MSG_FILAMENT_LOADING_T0 "Inserire filamento nell'estrusore 1. Click per continuare." +#define MSG_FILAMENT_LOADING_T1 "Inserire filamento nell'estrusore 2. Click per continuare." +#define MSG_FILAMENT_LOADING_T2 "Inserire filamento nell'estrusore 3. Click per continuare." +#define MSG_FILAMENT_LOADING_T3 "Inserire filamento nell'estrusore 4. Click per continuare." +#define MSG_CHANGE_EXTR "Cambio estrusore." + +#define MSG_FIL_ADJUSTING "Filamento in fase di regolazione. Attendere prego." +#define MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ "I filamenti sono regolati. Si prega di pulire l'ugello per la calibrazione. Click per continuare." +#define MSG_CALIBRATE_E "Calibra E" +#define MSG_E_CAL_KNOB "Girare la manopola affinche' il segno raggiunga il corpo dell'estrusore. Click per continuare." +#define MSG_MARK_FIL "Segnare il filamento a 100 mm di distanza dal corpo dell'estrusore. Click per continuare." +#define MSG_CLEAN_NOZZLE_E "Calibrazione E terminata. Si prega di pulire l'ugello. Click per continuare." +#define MSG_WAITING_TEMP "In attesa del raffreddamento della testina e del piatto" +#define MSG_FILAMENT_CLEAN "Il colore e' nitido?" +#define MSG_UNLOADING_FILAMENT "Rilasc. filamento" +#define MSG_PAPER "Porre un foglio sotto l'ugello durante la calibrazione dei primi 4 punti. In caso l'ugello muova il foglio spegnere prontamente la stampante." + +#define MSG_FINISHING_MOVEMENTS "Arresto in corso" +#define MSG_PRINT_PAUSED "Stampa in pausa" +#define MSG_RESUMING_PRINT "Stampa in ripresa" +#define MSG_PID_EXTRUDER "Calibrazione PID" +#define MSG_SET_TEMPERATURE "Imposta temperatura" +#define MSG_PID_FINISHED "Cal. PID completa" +#define MSG_PID_RUNNING "Cal. PID" + +#define MSG_CALIBRATE_PINDA "Calibrare" +#define MSG_CALIBRATION_PINDA_MENU "Taratura temp." +#define MSG_PINDA_NOT_CALIBRATED "Taratura della temperatura non ancora eseguita" +#define MSG_PINDA_PREHEAT "Riscald. PINDA" +#define MSG_TEMP_CALIBRATION "Cal. temp. " +#define MSG_TEMP_CALIBRATION_DONE "Taratura temperatura terminata. Fare click per continuare." +#define MSG_TEMP_CALIBRATION_ON "Cal. temp. [ON]" +#define MSG_TEMP_CALIBRATION_OFF "Cal. temp. [OFF]" + +#define MSG_LOAD_ALL "Caricare tutti" +#define MSG_LOAD_FILAMENT_1 "Caricare fil. 1" +#define MSG_LOAD_FILAMENT_2 "Caricare fil. 2" +#define MSG_LOAD_FILAMENT_3 "Caricare fil. 3" +#define MSG_LOAD_FILAMENT_4 "Caricare fil. 4" +#define MSG_UNLOAD_FILAMENT_1 "Rilasciare fil. 1" +#define MSG_UNLOAD_FILAMENT_2 "Rilasciare fil. 1" +#define MSG_UNLOAD_FILAMENT_3 "Rilasciare fil. 1" +#define MSG_UNLOAD_FILAMENT_4 "Rilasciare fil. 1" +#define MSG_UNLOAD_ALL "Rilasciare tutti" +#define MSG_PREPARE_FILAMENT "Preparare filamento" +#define MSG_ALL "Tutti" +#define MSG_USED "Usati nella stampa" +#define MSG_CURRENT "Attuale" +#define MSG_CHOOSE_EXTRUDER "Seleziona estrusore:" +#define MSG_EXTRUDER "Estrusore" +#define MSG_EXTRUDER_1 "Estrusore 1" +#define MSG_EXTRUDER_2 "Estrusore 2" +#define MSG_EXTRUDER_3 "Estrusore 3" +#define MSG_EXTRUDER_4 "Estrusore 4" \ No newline at end of file diff --git a/Firmware/language_pl.h b/Firmware/language_pl.h index 6df047c6c..3cd283ded 100644 --- a/Firmware/language_pl.h +++ b/Firmware/language_pl.h @@ -211,6 +211,7 @@ #define MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2 " z 9" #define MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1 "Okreslam wysokosc odniesienia punktu kalibracyjnego" #define MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2 " z 9" +#define MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION "Iteracja " #define MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND "Kalibr. XYZ nieudana. Kalibracyjny punkt podkladki nieznaleziony." #define MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED "Kalibracja XYZ niepowiedziona. Sprawdzic w instrukcji." @@ -248,8 +249,7 @@ #define MSG_FILAMENT_LOADING_T2 "Wloz filament do ekstrudera 3. Potwierdz przyciskiem." #define MSG_FILAMENT_LOADING_T3 "Wloz filament do ekstrudera 4. Potwierdz przyciskiem." #define MSG_CHANGE_EXTR "Zmienic ekstruder" -#define MSG_FIL_LOADED_CHECK "Czy filament jest wprowadzony?" -#define MSG_FIL_TUNING "Obrotem przycisku dostroj pozycje filamentu." + #define MSG_FIL_ADJUSTING "Przebiega wyrownanie filamentow. Prosze czekac." #define MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ "Dla prawidlowej kalibracji prosze oczyscic dysze. Potem potwierdzic przyciskiem." #define MSG_CALIBRATE_E "Kalibruj E" @@ -259,4 +259,43 @@ #define MSG_WAITING_TEMP "Oczekiwanie na wychlodzenie dyszy i podkladki." #define MSG_FILAMENT_CLEAN "Czy kolor jest czysty?" #define MSG_UNLOADING_FILAMENT "Wysuwam filament" -#define MSG_PAPER "Umiesc kartke papieru na podkladce i trzymaj pod dysza podczas pomiaru pierwszych 4 punktow. Jesli dysza zahaczy o papier, wylacz drukarke." \ No newline at end of file +#define MSG_PAPER "Umiesc kartke papieru na podkladce i trzymaj pod dysza podczas pomiaru pierwszych 4 punktow. Jesli dysza zahaczy o papier, wylacz drukarke." + +#define MSG_FINISHING_MOVEMENTS "Konczenie druku" +#define MSG_PRINT_PAUSED "Druk zatrzymany" +#define MSG_RESUMING_PRINT "Wznawianie druku" +#define MSG_PID_EXTRUDER "Kalibracja PID" +#define MSG_SET_TEMPERATURE "Ustawic temperature" +#define MSG_PID_FINISHED "Kal. PID zakonczona" +#define MSG_PID_RUNNING "Kal. PID" + +#define MSG_CALIBRATE_PINDA "Skalibrowac" +#define MSG_CALIBRATION_PINDA_MENU "Cieplna kalibr." +#define MSG_PINDA_NOT_CALIBRATED "Cieplna kalibracja nie byla przeprowadzona" +#define MSG_PINDA_PREHEAT "Grzanie PINDA" +#define MSG_TEMP_CALIBRATION "Ciepl. kal. " +#define MSG_TEMP_CALIBRATION_DONE "Cieplna kalibracja zakonczona. Kontynuuj przyciskiem" +#define MSG_TEMP_CALIBRATION_ON "Ciepl. kal. [ON]" +#define MSG_TEMP_CALIBRATION_OFF "Ciepl. kal. [OFF]" +#define MSG_PREPARE_FILAMENT "Przygotuj filament" + +#define MSG_LOAD_ALL "Zalad. wszystkie" +#define MSG_LOAD_FILAMENT_1 "Zaladowac fil. 1" +#define MSG_LOAD_FILAMENT_2 "Zaladowac fil. 2" +#define MSG_LOAD_FILAMENT_3 "Zaladowac fil. 3" +#define MSG_LOAD_FILAMENT_4 "Zaladowac fil. 4" +#define MSG_UNLOAD_FILAMENT_1 "Wyjac filament 1" +#define MSG_UNLOAD_FILAMENT_2 "Wyjac filament 2" +#define MSG_UNLOAD_FILAMENT_3 "Wyjac filament 3" +#define MSG_UNLOAD_FILAMENT_4 "Wyjac filament 4" +#define MSG_UNLOAD_ALL "Wyjac wszystkie" +#define MSG_PREPARE_FILAMENT "Przygotuj filament" +#define MSG_ALL "Wszystko" +#define MSG_USED "Uzyte przy druku" +#define MSG_CURRENT "Tylko aktualne" +#define MSG_CHOOSE_EXTRUDER "Wybierz ekstruder" +#define MSG_EXTRUDER "Ekstruder" +#define MSG_EXTRUDER_1 "Ekstruder 1" +#define MSG_EXTRUDER_2 "Ekstruder 2" +#define MSG_EXTRUDER_3 "Ekstruder 3" +#define MSG_EXTRUDER_4 "Ekstruder 4" \ No newline at end of file diff --git a/Firmware/le.sh b/Firmware/le.sh new file mode 100644 index 000000000..57646735e --- /dev/null +++ b/Firmware/le.sh @@ -0,0 +1,29 @@ +# line ending management script +# CRLF - windows default ('\r\n') +# LF - unix default ('\n') +# arguments: +# ?crlf - print all .cpp and .h files with CRLF line endings +# ?lf - print all .cpp and .h files with LF line endings +# crlf - replace line endings in all .cpp and .h files to CRLF +# lf - replace line endings in all .cpp and .h files to LF + +if [ "$1" == "?crlf" ] || [ $# -eq 0 ]; then + echo 'cpp and h files with CRLF line endings:' + find {*.cpp,*.h} -not -type d -exec file "{}" ";" | grep CRLF | sed 's/:.*//g' +elif [ "$1" == "?lf" ]; then + echo 'cpp and h files with LF line endings:' + find {*.cpp,*.h} -not -type d -exec file "{}" ";" | grep -v CRLF | sed 's/:.*//g' +fi +if [ "$1" == "crlf" ]; then + echo 'replacing LF with CRLF in all cpp and h files:' + find {*.cpp,*.h} -not -type d -exec file "{}" ";" | grep -v CRLF | sed 's/:.*//g' | while read fn; do + echo "$fn" + sed -i 's/$/\r/g' $fn + done +elif [ "$1" == "lf" ]; then + echo 'replacing CRLF with LF in all cpp and h files:' + find {*.cpp,*.h} -not -type d -exec file "{}" ";" | grep CRLF | sed 's/:.*//g' | while read fn; do + echo "$fn" + sed -i 's/\r\n/\n/g' $fn + done +fi diff --git a/Firmware/mesh_bed_calibration.cpp b/Firmware/mesh_bed_calibration.cpp index 38eb41c69..ca5312ace 100644 --- a/Firmware/mesh_bed_calibration.cpp +++ b/Firmware/mesh_bed_calibration.cpp @@ -1,2257 +1,2464 @@ -#include "Marlin.h" -#include "Configuration.h" -#include "ConfigurationStore.h" -#include "language_all.h" -#include "mesh_bed_calibration.h" -#include "mesh_bed_leveling.h" -#include "stepper.h" -#include "ultralcd.h" - -uint8_t world2machine_correction_mode; -float world2machine_rotation_and_skew[2][2]; -float world2machine_rotation_and_skew_inv[2][2]; -float world2machine_shift[2]; - -// Weight of the Y coordinate for the least squares fitting of the bed induction sensor targets. -// Only used for the first row of the points, which may not befully in reach of the sensor. -#define WEIGHT_FIRST_ROW_X_HIGH (1.f) -#define WEIGHT_FIRST_ROW_X_LOW (0.35f) -#define WEIGHT_FIRST_ROW_Y_HIGH (0.3f) -#define WEIGHT_FIRST_ROW_Y_LOW (0.0f) - -#define BED_ZERO_REF_X (- 22.f + X_PROBE_OFFSET_FROM_EXTRUDER) -#define BED_ZERO_REF_Y (- 0.6f + Y_PROBE_OFFSET_FROM_EXTRUDER) - -// Scaling of the real machine axes against the programmed dimensions in the firmware. -// The correction is tiny, here around 0.5mm on 250mm length. -//#define MACHINE_AXIS_SCALE_X ((250.f - 0.5f) / 250.f) -//#define MACHINE_AXIS_SCALE_Y ((250.f - 0.5f) / 250.f) -#define MACHINE_AXIS_SCALE_X 1.f -#define MACHINE_AXIS_SCALE_Y 1.f - -// 0.12 degrees equals to an offset of 0.5mm on 250mm length. -#define BED_SKEW_ANGLE_MILD (0.12f * M_PI / 180.f) -// 0.25 degrees equals to an offset of 1.1mm on 250mm length. -#define BED_SKEW_ANGLE_EXTREME (0.25f * M_PI / 180.f) - -#define BED_CALIBRATION_POINT_OFFSET_MAX_EUCLIDIAN (0.8f) -#define BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_X (0.8f) -#define BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_Y (1.5f) - -#define MIN_BED_SENSOR_POINT_RESPONSE_DMR (2.0f) - -//#define Y_MIN_POS_FOR_BED_CALIBRATION (MANUAL_Y_HOME_POS-0.2f) -#define Y_MIN_POS_FOR_BED_CALIBRATION (Y_MIN_POS) -// Distances toward the print bed edge may not be accurate. -#define Y_MIN_POS_CALIBRATION_POINT_ACCURATE (Y_MIN_POS + 3.f) -// When the measured point center is out of reach of the sensor, Y coordinate will be ignored -// by the Least Squares fitting and the X coordinate will be weighted low. -#define Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH (Y_MIN_POS - 0.5f) - -// Positions of the bed reference points in the machine coordinates, referenced to the P.I.N.D.A sensor. -// The points are ordered in a zig-zag fashion to speed up the calibration. -const float bed_ref_points[] PROGMEM = { - 13.f - BED_ZERO_REF_X, 6.4f - BED_ZERO_REF_Y, - 115.f - BED_ZERO_REF_X, 6.4f - BED_ZERO_REF_Y, - 216.f - BED_ZERO_REF_X, 6.4f - BED_ZERO_REF_Y, - - 216.f - BED_ZERO_REF_X, 104.4f - BED_ZERO_REF_Y, - 115.f - BED_ZERO_REF_X, 104.4f - BED_ZERO_REF_Y, - 13.f - BED_ZERO_REF_X, 104.4f - BED_ZERO_REF_Y, - - 13.f - BED_ZERO_REF_X, 202.4f - BED_ZERO_REF_Y, - 115.f - BED_ZERO_REF_X, 202.4f - BED_ZERO_REF_Y, - 216.f - BED_ZERO_REF_X, 202.4f - BED_ZERO_REF_Y -}; - -// Positions of the bed reference points in the machine coordinates, referenced to the P.I.N.D.A sensor. -// The points are the following: center front, center right, center rear, center left. -const float bed_ref_points_4[] PROGMEM = { - 115.f - BED_ZERO_REF_X, 6.4f - BED_ZERO_REF_Y, - 216.f - BED_ZERO_REF_X, 104.4f - BED_ZERO_REF_Y, - 115.f - BED_ZERO_REF_X, 202.4f - BED_ZERO_REF_Y, - 13.f - BED_ZERO_REF_X, 104.4f - BED_ZERO_REF_Y -}; - -static inline float sqr(float x) { return x * x; } - -// Weight of a point coordinate in a least squares optimization. -// The first row of points may not be fully reachable -// and the y values may be shortened a bit by the bed carriage -// pulling the belt up. -static inline float point_weight_x(const uint8_t i, const float &y) -{ - float w = 1.f; - if (i < 3) { - if (y >= Y_MIN_POS_CALIBRATION_POINT_ACCURATE) { - w = WEIGHT_FIRST_ROW_X_HIGH; - } else if (y < Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH) { - // If the point is fully outside, give it some weight. - w = WEIGHT_FIRST_ROW_X_LOW; - } else { - // Linearly interpolate the weight from 1 to WEIGHT_FIRST_ROW_X. - float t = (y - Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH) / (Y_MIN_POS_CALIBRATION_POINT_ACCURATE - Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH); - w = (1.f - t) * WEIGHT_FIRST_ROW_X_LOW + t * WEIGHT_FIRST_ROW_X_HIGH; - } - } - return w; -} - -// Weight of a point coordinate in a least squares optimization. -// The first row of points may not be fully reachable -// and the y values may be shortened a bit by the bed carriage -// pulling the belt up. -static inline float point_weight_y(const uint8_t i, const float &y) -{ - float w = 1.f; - if (i < 3) { - if (y >= Y_MIN_POS_CALIBRATION_POINT_ACCURATE) { - w = WEIGHT_FIRST_ROW_Y_HIGH; - } else if (y < Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH) { - // If the point is fully outside, give it some weight. - w = WEIGHT_FIRST_ROW_Y_LOW; - } else { - // Linearly interpolate the weight from 1 to WEIGHT_FIRST_ROW_X. - float t = (y - Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH) / (Y_MIN_POS_CALIBRATION_POINT_ACCURATE - Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH); - w = (1.f - t) * WEIGHT_FIRST_ROW_Y_LOW + t * WEIGHT_FIRST_ROW_Y_HIGH; - } - } - return w; -} - -// Non-Linear Least Squares fitting of the bed to the measured induction points -// using the Gauss-Newton method. -// This method will maintain a unity length of the machine axes, -// which is the correct approach if the sensor points are not measured precisely. -BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS( - // Matrix of maximum 9 2D points (18 floats) - const float *measured_pts, - uint8_t npts, - const float *true_pts, - // Resulting correction matrix. - float *vec_x, - float *vec_y, - float *cntr, - // Temporary values, 49-18-(2*3)=25 floats - // , float *temp - int8_t verbosity_level - ) -{ - if (verbosity_level >= 10) { - // Show the initial state, before the fitting. - SERIAL_ECHOPGM("X vector, initial: "); - MYSERIAL.print(vec_x[0], 5); - SERIAL_ECHOPGM(", "); - MYSERIAL.print(vec_x[1], 5); - SERIAL_ECHOLNPGM(""); - - SERIAL_ECHOPGM("Y vector, initial: "); - MYSERIAL.print(vec_y[0], 5); - SERIAL_ECHOPGM(", "); - MYSERIAL.print(vec_y[1], 5); - SERIAL_ECHOLNPGM(""); - - SERIAL_ECHOPGM("center, initial: "); - MYSERIAL.print(cntr[0], 5); - SERIAL_ECHOPGM(", "); - MYSERIAL.print(cntr[1], 5); - SERIAL_ECHOLNPGM(""); - - for (uint8_t i = 0; i < npts; ++i) { - SERIAL_ECHOPGM("point #"); - MYSERIAL.print(int(i)); - SERIAL_ECHOPGM(" measured: ("); - MYSERIAL.print(measured_pts[i * 2], 5); - SERIAL_ECHOPGM(", "); - MYSERIAL.print(measured_pts[i * 2 + 1], 5); - SERIAL_ECHOPGM("); target: ("); - MYSERIAL.print(pgm_read_float(true_pts + i * 2), 5); - SERIAL_ECHOPGM(", "); - MYSERIAL.print(pgm_read_float(true_pts + i * 2 + 1), 5); - SERIAL_ECHOPGM("), error: "); - MYSERIAL.print(sqrt( - sqr(pgm_read_float(true_pts + i * 2) - measured_pts[i * 2]) + - sqr(pgm_read_float(true_pts + i * 2 + 1) - measured_pts[i * 2 + 1])), 5); - SERIAL_ECHOLNPGM(""); - } - delay_keep_alive(100); - } - - // Run some iterations of the Gauss-Newton method of non-linear least squares. - // Initial set of parameters: - // X,Y offset - cntr[0] = 0.f; - cntr[1] = 0.f; - // Rotation of the machine X axis from the bed X axis. - float a1 = 0; - // Rotation of the machine Y axis from the bed Y axis. - float a2 = 0; - for (int8_t iter = 0; iter < 100; ++iter) { - float c1 = cos(a1) * MACHINE_AXIS_SCALE_X; - float s1 = sin(a1) * MACHINE_AXIS_SCALE_X; - float c2 = cos(a2) * MACHINE_AXIS_SCALE_Y; - float s2 = sin(a2) * MACHINE_AXIS_SCALE_Y; - // Prepare the Normal equation for the Gauss-Newton method. - float A[4][4] = { 0.f }; - float b[4] = { 0.f }; - float acc; - for (uint8_t r = 0; r < 4; ++r) { - for (uint8_t c = 0; c < 4; ++c) { - acc = 0; - // J^T times J - for (uint8_t i = 0; i < npts; ++i) { - // First for the residuum in the x axis: - if (r != 1 && c != 1) { - float a = - (r == 0) ? 1.f : - ((r == 2) ? (-s1 * measured_pts[2 * i]) : - (-c2 * measured_pts[2 * i + 1])); - float b = - (c == 0) ? 1.f : - ((c == 2) ? (-s1 * measured_pts[2 * i]) : - (-c2 * measured_pts[2 * i + 1])); - float w = point_weight_x(i, measured_pts[2 * i + 1]); - acc += a * b * w; - } - // Second for the residuum in the y axis. - // The first row of the points have a low weight, because their position may not be known - // with a sufficient accuracy. - if (r != 0 && c != 0) { - float a = - (r == 1) ? 1.f : - ((r == 2) ? ( c1 * measured_pts[2 * i]) : - (-s2 * measured_pts[2 * i + 1])); - float b = - (c == 1) ? 1.f : - ((c == 2) ? ( c1 * measured_pts[2 * i]) : - (-s2 * measured_pts[2 * i + 1])); - float w = point_weight_y(i, measured_pts[2 * i + 1]); - acc += a * b * w; - } - } - A[r][c] = acc; - } - // J^T times f(x) - acc = 0.f; - for (uint8_t i = 0; i < npts; ++i) { - { - float j = - (r == 0) ? 1.f : - ((r == 1) ? 0.f : - ((r == 2) ? (-s1 * measured_pts[2 * i]) : - (-c2 * measured_pts[2 * i + 1]))); - float fx = c1 * measured_pts[2 * i] - s2 * measured_pts[2 * i + 1] + cntr[0] - pgm_read_float(true_pts + i * 2); - float w = point_weight_x(i, measured_pts[2 * i + 1]); - acc += j * fx * w; - } - { - float j = - (r == 0) ? 0.f : - ((r == 1) ? 1.f : - ((r == 2) ? ( c1 * measured_pts[2 * i]) : - (-s2 * measured_pts[2 * i + 1]))); - float fy = s1 * measured_pts[2 * i] + c2 * measured_pts[2 * i + 1] + cntr[1] - pgm_read_float(true_pts + i * 2 + 1); - float w = point_weight_y(i, measured_pts[2 * i + 1]); - acc += j * fy * w; - } - } - b[r] = -acc; - } - - // Solve for h by a Gauss iteration method. - float h[4] = { 0.f }; - for (uint8_t gauss_iter = 0; gauss_iter < 100; ++gauss_iter) { - h[0] = (b[0] - A[0][1] * h[1] - A[0][2] * h[2] - A[0][3] * h[3]) / A[0][0]; - h[1] = (b[1] - A[1][0] * h[0] - A[1][2] * h[2] - A[1][3] * h[3]) / A[1][1]; - h[2] = (b[2] - A[2][0] * h[0] - A[2][1] * h[1] - A[2][3] * h[3]) / A[2][2]; - h[3] = (b[3] - A[3][0] * h[0] - A[3][1] * h[1] - A[3][2] * h[2]) / A[3][3]; - } - - // and update the current position with h. - // It may be better to use the Levenberg-Marquart method here, - // but because we are very close to the solution alread, - // the simple Gauss-Newton non-linear Least Squares method works well enough. - cntr[0] += h[0]; - cntr[1] += h[1]; - a1 += h[2]; - a2 += h[3]; - - if (verbosity_level >= 20) { - SERIAL_ECHOPGM("iteration: "); - MYSERIAL.print(iter, 0); - SERIAL_ECHOPGM("correction vector: "); - MYSERIAL.print(h[0], 5); - SERIAL_ECHOPGM(", "); - MYSERIAL.print(h[1], 5); - SERIAL_ECHOPGM(", "); - MYSERIAL.print(h[2], 5); - SERIAL_ECHOPGM(", "); - MYSERIAL.print(h[3], 5); - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOPGM("corrected x/y: "); - MYSERIAL.print(cntr[0], 5); - SERIAL_ECHOPGM(", "); - MYSERIAL.print(cntr[0], 5); - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOPGM("corrected angles: "); - MYSERIAL.print(180.f * a1 / M_PI, 5); - SERIAL_ECHOPGM(", "); - MYSERIAL.print(180.f * a2 / M_PI, 5); - SERIAL_ECHOLNPGM(""); - } - } - - vec_x[0] = cos(a1) * MACHINE_AXIS_SCALE_X; - vec_x[1] = sin(a1) * MACHINE_AXIS_SCALE_X; - vec_y[0] = -sin(a2) * MACHINE_AXIS_SCALE_Y; - vec_y[1] = cos(a2) * MACHINE_AXIS_SCALE_Y; - - BedSkewOffsetDetectionResultType result = BED_SKEW_OFFSET_DETECTION_PERFECT; - { - float angleDiff = fabs(a2 - a1); - if (angleDiff > BED_SKEW_ANGLE_MILD) - result = (angleDiff > BED_SKEW_ANGLE_EXTREME) ? - BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME : - BED_SKEW_OFFSET_DETECTION_SKEW_MILD; - if (fabs(a1) > BED_SKEW_ANGLE_EXTREME || - fabs(a2) > BED_SKEW_ANGLE_EXTREME) - result = BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME; - } - - if (verbosity_level >= 1) { - SERIAL_ECHOPGM("correction angles: "); - MYSERIAL.print(180.f * a1 / M_PI, 5); - SERIAL_ECHOPGM(", "); - MYSERIAL.print(180.f * a2 / M_PI, 5); - SERIAL_ECHOLNPGM(""); - } - - if (verbosity_level >= 10) { - // Show the adjusted state, before the fitting. - SERIAL_ECHOPGM("X vector new, inverted: "); - MYSERIAL.print(vec_x[0], 5); - SERIAL_ECHOPGM(", "); - MYSERIAL.print(vec_x[1], 5); - SERIAL_ECHOLNPGM(""); - - SERIAL_ECHOPGM("Y vector new, inverted: "); - MYSERIAL.print(vec_y[0], 5); - SERIAL_ECHOPGM(", "); - MYSERIAL.print(vec_y[1], 5); - SERIAL_ECHOLNPGM(""); - - SERIAL_ECHOPGM("center new, inverted: "); - MYSERIAL.print(cntr[0], 5); - SERIAL_ECHOPGM(", "); - MYSERIAL.print(cntr[1], 5); - SERIAL_ECHOLNPGM(""); - delay_keep_alive(100); - - SERIAL_ECHOLNPGM("Error after correction: "); - } - - // Measure the error after correction. - for (uint8_t i = 0; i < npts; ++i) { - float x = vec_x[0] * measured_pts[i * 2] + vec_y[0] * measured_pts[i * 2 + 1] + cntr[0]; - float y = vec_x[1] * measured_pts[i * 2] + vec_y[1] * measured_pts[i * 2 + 1] + cntr[1]; - float errX = sqr(pgm_read_float(true_pts + i * 2) - x); - float errY = sqr(pgm_read_float(true_pts + i * 2 + 1) - y); - float err = sqrt(errX + errY); - if (i < 3) { - float w = point_weight_y(i, measured_pts[2 * i + 1]); - if (sqrt(errX) > BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_X || - (w != 0.f && sqrt(errY) > BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_Y)) - result = BED_SKEW_OFFSET_DETECTION_FITTING_FAILED; - } else { - if (err > BED_CALIBRATION_POINT_OFFSET_MAX_EUCLIDIAN) - result = BED_SKEW_OFFSET_DETECTION_FITTING_FAILED; - } - if (verbosity_level >= 10) { - SERIAL_ECHOPGM("point #"); - MYSERIAL.print(int(i)); - SERIAL_ECHOPGM(" measured: ("); - MYSERIAL.print(measured_pts[i * 2], 5); - SERIAL_ECHOPGM(", "); - MYSERIAL.print(measured_pts[i * 2 + 1], 5); - SERIAL_ECHOPGM("); corrected: ("); - MYSERIAL.print(x, 5); - SERIAL_ECHOPGM(", "); - MYSERIAL.print(y, 5); - SERIAL_ECHOPGM("); target: ("); - MYSERIAL.print(pgm_read_float(true_pts + i * 2), 5); - SERIAL_ECHOPGM(", "); - MYSERIAL.print(pgm_read_float(true_pts + i * 2 + 1), 5); - SERIAL_ECHOPGM("), error: "); - MYSERIAL.print(err); - SERIAL_ECHOLNPGM(""); - } - } - - #if 0 - if (result == BED_SKEW_OFFSET_DETECTION_PERFECT && fabs(a1) < BED_SKEW_ANGLE_MILD && fabs(a2) < BED_SKEW_ANGLE_MILD) { - if (verbosity_level > 0) - SERIAL_ECHOLNPGM("Very little skew detected. Disabling skew correction."); - // Just disable the skew correction. - vec_x[0] = MACHINE_AXIS_SCALE_X; - vec_x[1] = 0.f; - vec_y[0] = 0.f; - vec_y[1] = MACHINE_AXIS_SCALE_Y; - } - #else - if (result == BED_SKEW_OFFSET_DETECTION_PERFECT) { - if (verbosity_level > 0) - SERIAL_ECHOLNPGM("Very little skew detected. Orthogonalizing the axes."); - // Orthogonalize the axes. - a1 = 0.5f * (a1 + a2); - vec_x[0] = cos(a1) * MACHINE_AXIS_SCALE_X; - vec_x[1] = sin(a1) * MACHINE_AXIS_SCALE_X; - vec_y[0] = -sin(a1) * MACHINE_AXIS_SCALE_Y; - vec_y[1] = cos(a1) * MACHINE_AXIS_SCALE_Y; - // Refresh the offset. - cntr[0] = 0.f; - cntr[1] = 0.f; - float wx = 0.f; - float wy = 0.f; - for (int8_t i = 0; i < npts; ++ i) { - float x = vec_x[0] * measured_pts[i * 2] + vec_y[0] * measured_pts[i * 2 + 1]; - float y = vec_x[1] * measured_pts[i * 2] + vec_y[1] * measured_pts[i * 2 + 1]; - float w = point_weight_x(i, y); - cntr[0] += w * (pgm_read_float(true_pts + i * 2) - x); - wx += w; - if (verbosity_level >= 20) { - MYSERIAL.print(i); - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOLNPGM("Weight_x:"); - MYSERIAL.print(w); - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOLNPGM("cntr[0]:"); - MYSERIAL.print(cntr[0]); - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOLNPGM("wx:"); - MYSERIAL.print(wx); - } - w = point_weight_y(i, y); - cntr[1] += w * (pgm_read_float(true_pts + i * 2 + 1) - y); - wy += w; - - if (verbosity_level >= 20) { - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOLNPGM("Weight_y:"); - MYSERIAL.print(w); - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOLNPGM("cntr[1]:"); - MYSERIAL.print(cntr[1]); - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOLNPGM("wy:"); - MYSERIAL.print(wy); - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOLNPGM(""); - } - } - cntr[0] /= wx; - cntr[1] /= wy; - if (verbosity_level >= 20) { - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOLNPGM("Final cntr values:"); - SERIAL_ECHOLNPGM("cntr[0]:"); - MYSERIAL.print(cntr[0]); - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOLNPGM("cntr[1]:"); - MYSERIAL.print(cntr[1]); - SERIAL_ECHOLNPGM(""); - } - - } - #endif - - // Invert the transformation matrix made of vec_x, vec_y and cntr. - { - float d = vec_x[0] * vec_y[1] - vec_x[1] * vec_y[0]; - float Ainv[2][2] = { - { vec_y[1] / d, -vec_y[0] / d }, - { -vec_x[1] / d, vec_x[0] / d } - }; - float cntrInv[2] = { - -Ainv[0][0] * cntr[0] - Ainv[0][1] * cntr[1], - -Ainv[1][0] * cntr[0] - Ainv[1][1] * cntr[1] - }; - vec_x[0] = Ainv[0][0]; - vec_x[1] = Ainv[1][0]; - vec_y[0] = Ainv[0][1]; - vec_y[1] = Ainv[1][1]; - cntr[0] = cntrInv[0]; - cntr[1] = cntrInv[1]; - } - - if (verbosity_level >= 1) { - // Show the adjusted state, before the fitting. - SERIAL_ECHOPGM("X vector, adjusted: "); - MYSERIAL.print(vec_x[0], 5); - SERIAL_ECHOPGM(", "); - MYSERIAL.print(vec_x[1], 5); - SERIAL_ECHOLNPGM(""); - - SERIAL_ECHOPGM("Y vector, adjusted: "); - MYSERIAL.print(vec_y[0], 5); - SERIAL_ECHOPGM(", "); - MYSERIAL.print(vec_y[1], 5); - SERIAL_ECHOLNPGM(""); - - SERIAL_ECHOPGM("center, adjusted: "); - MYSERIAL.print(cntr[0], 5); - SERIAL_ECHOPGM(", "); - MYSERIAL.print(cntr[1], 5); - SERIAL_ECHOLNPGM(""); - delay_keep_alive(100); - } - - if (verbosity_level >= 2) { - SERIAL_ECHOLNPGM("Difference after correction: "); - for (uint8_t i = 0; i < npts; ++i) { - float x = vec_x[0] * pgm_read_float(true_pts + i * 2) + vec_y[0] * pgm_read_float(true_pts + i * 2 + 1) + cntr[0]; - float y = vec_x[1] * pgm_read_float(true_pts + i * 2) + vec_y[1] * pgm_read_float(true_pts + i * 2 + 1) + cntr[1]; - SERIAL_ECHOPGM("point #"); - MYSERIAL.print(int(i)); - SERIAL_ECHOPGM("measured: ("); - MYSERIAL.print(measured_pts[i * 2], 5); - SERIAL_ECHOPGM(", "); - MYSERIAL.print(measured_pts[i * 2 + 1], 5); - SERIAL_ECHOPGM("); measured-corrected: ("); - MYSERIAL.print(x, 5); - SERIAL_ECHOPGM(", "); - MYSERIAL.print(y, 5); - SERIAL_ECHOPGM("); target: ("); - MYSERIAL.print(pgm_read_float(true_pts + i * 2), 5); - SERIAL_ECHOPGM(", "); - MYSERIAL.print(pgm_read_float(true_pts + i * 2 + 1), 5); - SERIAL_ECHOPGM("), error: "); - MYSERIAL.print(sqrt(sqr(measured_pts[i * 2] - x) + sqr(measured_pts[i * 2 + 1] - y))); - SERIAL_ECHOLNPGM(""); - } - delay_keep_alive(100); - } - - return result; -} - -void reset_bed_offset_and_skew() -{ - eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_CENTER+0), 0x0FFFFFFFF); - eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_CENTER+4), 0x0FFFFFFFF); - eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_VEC_X +0), 0x0FFFFFFFF); - eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_VEC_X +4), 0x0FFFFFFFF); - eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_VEC_Y +0), 0x0FFFFFFFF); - eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_VEC_Y +4), 0x0FFFFFFFF); - - // Reset the 8 16bit offsets. - for (int8_t i = 0; i < 4; ++ i) - eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_Z_JITTER+i*4), 0x0FFFFFFFF); -} - -bool is_bed_z_jitter_data_valid() -// offsets of the Z heiths of the calibration points from the first point are saved as 16bit signed int, scaled to tenths of microns -{ - for (int8_t i = 0; i < 8; ++ i) - if (eeprom_read_word((uint16_t*)(EEPROM_BED_CALIBRATION_Z_JITTER+i*2)) == 0x0FFFF) - return false; - return true; -} - -static void world2machine_update(const float vec_x[2], const float vec_y[2], const float cntr[2]) -{ - world2machine_rotation_and_skew[0][0] = vec_x[0]; - world2machine_rotation_and_skew[1][0] = vec_x[1]; - world2machine_rotation_and_skew[0][1] = vec_y[0]; - world2machine_rotation_and_skew[1][1] = vec_y[1]; - world2machine_shift[0] = cntr[0]; - world2machine_shift[1] = cntr[1]; - // No correction. - world2machine_correction_mode = WORLD2MACHINE_CORRECTION_NONE; - if (world2machine_shift[0] != 0.f || world2machine_shift[1] != 0.f) - // Shift correction. - world2machine_correction_mode |= WORLD2MACHINE_CORRECTION_SHIFT; - if (world2machine_rotation_and_skew[0][0] != 1.f || world2machine_rotation_and_skew[0][1] != 0.f || - world2machine_rotation_and_skew[1][0] != 0.f || world2machine_rotation_and_skew[1][1] != 1.f) { - // Rotation & skew correction. - world2machine_correction_mode |= WORLD2MACHINE_CORRECTION_SKEW; - // Invert the world2machine matrix. - float d = world2machine_rotation_and_skew[0][0] * world2machine_rotation_and_skew[1][1] - world2machine_rotation_and_skew[1][0] * world2machine_rotation_and_skew[0][1]; - world2machine_rotation_and_skew_inv[0][0] = world2machine_rotation_and_skew[1][1] / d; - world2machine_rotation_and_skew_inv[0][1] = -world2machine_rotation_and_skew[0][1] / d; - world2machine_rotation_and_skew_inv[1][0] = -world2machine_rotation_and_skew[1][0] / d; - world2machine_rotation_and_skew_inv[1][1] = world2machine_rotation_and_skew[0][0] / d; - } else { - world2machine_rotation_and_skew_inv[0][0] = 1.f; - world2machine_rotation_and_skew_inv[0][1] = 0.f; - world2machine_rotation_and_skew_inv[1][0] = 0.f; - world2machine_rotation_and_skew_inv[1][1] = 1.f; - } -} - -void world2machine_reset() -{ - const float vx[] = { 1.f, 0.f }; - const float vy[] = { 0.f, 1.f }; - const float cntr[] = { 0.f, 0.f }; - world2machine_update(vx, vy, cntr); -} - -void world2machine_revert_to_uncorrected() -{ - if (world2machine_correction_mode != WORLD2MACHINE_CORRECTION_NONE) { - // Reset the machine correction matrix. - const float vx[] = { 1.f, 0.f }; - const float vy[] = { 0.f, 1.f }; - const float cntr[] = { 0.f, 0.f }; - world2machine_update(vx, vy, cntr); - // Wait for the motors to stop and update the current position with the absolute values. - st_synchronize(); - current_position[X_AXIS] = st_get_position_mm(X_AXIS); - current_position[Y_AXIS] = st_get_position_mm(Y_AXIS); - } -} - -static inline bool vec_undef(const float v[2]) -{ - const uint32_t *vx = (const uint32_t*)v; - return vx[0] == 0x0FFFFFFFF || vx[1] == 0x0FFFFFFFF; -} - -void world2machine_initialize() -{ -// SERIAL_ECHOLNPGM("world2machine_initialize()"); - float cntr[2] = { - eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_CENTER+0)), - eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_CENTER+4)) - }; - float vec_x[2] = { - eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_X +0)), - eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_X +4)) - }; - float vec_y[2] = { - eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y +0)), - eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y +4)) - }; - - bool reset = false; - if (vec_undef(cntr) || vec_undef(vec_x) || vec_undef(vec_y)) { - // SERIAL_ECHOLNPGM("Undefined bed correction matrix."); - reset = true; - } - else { - // Length of the vec_x shall be close to unity. - float l = sqrt(vec_x[0] * vec_x[0] + vec_x[1] * vec_x[1]); - if (l < 0.9 || l > 1.1) { - SERIAL_ECHOLNPGM("X vector length:"); - MYSERIAL.println(l); - SERIAL_ECHOLNPGM("Invalid bed correction matrix. Length of the X vector out of range."); - reset = true; - } - // Length of the vec_y shall be close to unity. - l = sqrt(vec_y[0] * vec_y[0] + vec_y[1] * vec_y[1]); - if (l < 0.9 || l > 1.1) { - SERIAL_ECHOLNPGM("Y vector length:"); - MYSERIAL.println(l); - SERIAL_ECHOLNPGM("Invalid bed correction matrix. Length of the Y vector out of range."); - reset = true; - } - // Correction of the zero point shall be reasonably small. - l = sqrt(cntr[0] * cntr[0] + cntr[1] * cntr[1]); - if (l > 15.f) { - SERIAL_ECHOLNPGM("Zero point correction:"); - MYSERIAL.println(l); - SERIAL_ECHOLNPGM("Invalid bed correction matrix. Shift out of range."); - reset = true; - } - // vec_x and vec_y shall be nearly perpendicular. - l = vec_x[0] * vec_y[0] + vec_x[1] * vec_y[1]; - if (fabs(l) > 0.1f) { - SERIAL_ECHOLNPGM("Invalid bed correction matrix. X/Y axes are far from being perpendicular."); - reset = true; - } - } - - if (reset) { - SERIAL_ECHOLNPGM("Invalid bed correction matrix. Resetting to identity."); - reset_bed_offset_and_skew(); - world2machine_reset(); - } else { - world2machine_update(vec_x, vec_y, cntr); - /* - SERIAL_ECHOPGM("world2machine_initialize() loaded: "); - MYSERIAL.print(world2machine_rotation_and_skew[0][0], 5); - SERIAL_ECHOPGM(", "); - MYSERIAL.print(world2machine_rotation_and_skew[0][1], 5); - SERIAL_ECHOPGM(", "); - MYSERIAL.print(world2machine_rotation_and_skew[1][0], 5); - SERIAL_ECHOPGM(", "); - MYSERIAL.print(world2machine_rotation_and_skew[1][1], 5); - SERIAL_ECHOPGM(", offset "); - MYSERIAL.print(world2machine_shift[0], 5); - SERIAL_ECHOPGM(", "); - MYSERIAL.print(world2machine_shift[1], 5); - SERIAL_ECHOLNPGM(""); - */ - } -} - -// When switching from absolute to corrected coordinates, -// this will get the absolute coordinates from the servos, -// applies the inverse world2machine transformation -// and stores the result into current_position[x,y]. -void world2machine_update_current() -{ - float x = current_position[X_AXIS] - world2machine_shift[0]; - float y = current_position[Y_AXIS] - world2machine_shift[1]; - current_position[X_AXIS] = world2machine_rotation_and_skew_inv[0][0] * x + world2machine_rotation_and_skew_inv[0][1] * y; - current_position[Y_AXIS] = world2machine_rotation_and_skew_inv[1][0] * x + world2machine_rotation_and_skew_inv[1][1] * y; -} - -static inline void go_xyz(float x, float y, float z, float fr) -{ - plan_buffer_line(x, y, z, current_position[E_AXIS], fr, active_extruder); - st_synchronize(); -} - -static inline void go_xy(float x, float y, float fr) -{ - plan_buffer_line(x, y, current_position[Z_AXIS], current_position[E_AXIS], fr, active_extruder); - st_synchronize(); -} - -static inline void go_to_current(float fr) -{ - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], fr, active_extruder); - st_synchronize(); -} - -static inline void update_current_position_xyz() -{ - current_position[X_AXIS] = st_get_position_mm(X_AXIS); - current_position[Y_AXIS] = st_get_position_mm(Y_AXIS); - current_position[Z_AXIS] = st_get_position_mm(Z_AXIS); - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); -} - -static inline void update_current_position_z() -{ - current_position[Z_AXIS] = st_get_position_mm(Z_AXIS); - plan_set_z_position(current_position[Z_AXIS]); -} - -// At the current position, find the Z stop. -inline bool find_bed_induction_sensor_point_z(float minimum_z, uint8_t n_iter) -{ -// SERIAL_ECHOLNPGM("find_bed_induction_sensor_point_z 1"); - bool endstops_enabled = enable_endstops(true); - bool endstop_z_enabled = enable_z_endstop(false); - float z = 0.f; - endstop_z_hit_on_purpose(); - - // move down until you find the bed - current_position[Z_AXIS] = minimum_z; - go_to_current(homing_feedrate[Z_AXIS]/60); - // we have to let the planner know where we are right now as it is not where we said to go. - update_current_position_z(); - if (! endstop_z_hit_on_purpose()) - goto error; - - for (uint8_t i = 0; i < n_iter; ++ i) { - // Move up the retract distance. - current_position[Z_AXIS] += .5f; - go_to_current(homing_feedrate[Z_AXIS]/60); - // Move back down slowly to find bed. - current_position[Z_AXIS] = minimum_z; - go_to_current(homing_feedrate[Z_AXIS]/(4*60)); - // we have to let the planner know where we are right now as it is not where we said to go. - update_current_position_z(); - if (! endstop_z_hit_on_purpose()) - goto error; -// SERIAL_ECHOPGM("Bed find_bed_induction_sensor_point_z low, height: "); -// MYSERIAL.print(current_position[Z_AXIS], 5); -// SERIAL_ECHOLNPGM(""); - z += current_position[Z_AXIS]; - } - current_position[Z_AXIS] = z; - if (n_iter > 1) - current_position[Z_AXIS] /= float(n_iter); - - enable_endstops(endstops_enabled); - enable_z_endstop(endstop_z_enabled); -// SERIAL_ECHOLNPGM("find_bed_induction_sensor_point_z 3"); - return true; - -error: -// SERIAL_ECHOLNPGM("find_bed_induction_sensor_point_z 4"); - enable_endstops(endstops_enabled); - enable_z_endstop(endstop_z_enabled); - return false; -} - -// Search around the current_position[X,Y], -// look for the induction sensor response. -// Adjust the current_position[X,Y,Z] to the center of the target dot and its response Z coordinate. -#define FIND_BED_INDUCTION_SENSOR_POINT_X_RADIUS (8.f) -#define FIND_BED_INDUCTION_SENSOR_POINT_Y_RADIUS (6.f) -#define FIND_BED_INDUCTION_SENSOR_POINT_XY_STEP (1.f) -#define FIND_BED_INDUCTION_SENSOR_POINT_Z_STEP (0.2f) -inline bool find_bed_induction_sensor_point_xy() -{ - float feedrate = homing_feedrate[X_AXIS] / 60.f; - bool found = false; - - { - float x0 = current_position[X_AXIS] - FIND_BED_INDUCTION_SENSOR_POINT_X_RADIUS; - float x1 = current_position[X_AXIS] + FIND_BED_INDUCTION_SENSOR_POINT_X_RADIUS; - float y0 = current_position[Y_AXIS] - FIND_BED_INDUCTION_SENSOR_POINT_Y_RADIUS; - float y1 = current_position[Y_AXIS] + FIND_BED_INDUCTION_SENSOR_POINT_Y_RADIUS; - uint8_t nsteps_y; - uint8_t i; - if (x0 < X_MIN_POS) - x0 = X_MIN_POS; - if (x1 > X_MAX_POS) - x1 = X_MAX_POS; - if (y0 < Y_MIN_POS_FOR_BED_CALIBRATION) - y0 = Y_MIN_POS_FOR_BED_CALIBRATION; - if (y1 > Y_MAX_POS) - y1 = Y_MAX_POS; - nsteps_y = int(ceil((y1 - y0) / FIND_BED_INDUCTION_SENSOR_POINT_XY_STEP)); - - enable_endstops(false); - bool dir_positive = true; - -// go_xyz(current_position[X_AXIS], current_position[Y_AXIS], MESH_HOME_Z_SEARCH, homing_feedrate[Z_AXIS]/60); - go_xyz(x0, y0, current_position[Z_AXIS], feedrate); - // Continously lower the Z axis. - endstops_hit_on_purpose(); - enable_z_endstop(true); - while (current_position[Z_AXIS] > -10.f) { - // Do nsteps_y zig-zag movements. - current_position[Y_AXIS] = y0; - for (i = 0; i < nsteps_y; current_position[Y_AXIS] += (y1 - y0) / float(nsteps_y - 1), ++ i) { - // Run with a slightly decreasing Z axis, zig-zag movement. Stop at the Z end-stop. - current_position[Z_AXIS] -= FIND_BED_INDUCTION_SENSOR_POINT_Z_STEP / float(nsteps_y); - go_xyz(dir_positive ? x1 : x0, current_position[Y_AXIS], current_position[Z_AXIS], feedrate); - dir_positive = ! dir_positive; - if (endstop_z_hit_on_purpose()) - goto endloop; - } - for (i = 0; i < nsteps_y; current_position[Y_AXIS] -= (y1 - y0) / float(nsteps_y - 1), ++ i) { - // Run with a slightly decreasing Z axis, zig-zag movement. Stop at the Z end-stop. - current_position[Z_AXIS] -= FIND_BED_INDUCTION_SENSOR_POINT_Z_STEP / float(nsteps_y); - go_xyz(dir_positive ? x1 : x0, current_position[Y_AXIS], current_position[Z_AXIS], feedrate); - dir_positive = ! dir_positive; - if (endstop_z_hit_on_purpose()) - goto endloop; - } - } - endloop: -// SERIAL_ECHOLN("First hit"); - - // we have to let the planner know where we are right now as it is not where we said to go. - update_current_position_xyz(); - - // Search in this plane for the first hit. Zig-zag first in X, then in Y axis. - for (int8_t iter = 0; iter < 3; ++ iter) { - if (iter > 0) { - // Slightly lower the Z axis to get a reliable trigger. - current_position[Z_AXIS] -= 0.02f; - go_xyz(current_position[X_AXIS], current_position[Y_AXIS], MESH_HOME_Z_SEARCH, homing_feedrate[Z_AXIS]/60); - } - - // Do nsteps_y zig-zag movements. - float a, b; - enable_endstops(false); - enable_z_endstop(false); - current_position[Y_AXIS] = y0; - go_xy(x0, current_position[Y_AXIS], feedrate); - enable_z_endstop(true); - found = false; - for (i = 0, dir_positive = true; i < nsteps_y; current_position[Y_AXIS] += (y1 - y0) / float(nsteps_y - 1), ++ i, dir_positive = ! dir_positive) { - go_xy(dir_positive ? x1 : x0, current_position[Y_AXIS], feedrate); - if (endstop_z_hit_on_purpose()) { - found = true; - break; - } - } - update_current_position_xyz(); - if (! found) { -// SERIAL_ECHOLN("Search in Y - not found"); - continue; - } -// SERIAL_ECHOLN("Search in Y - found"); - a = current_position[Y_AXIS]; - - enable_z_endstop(false); - current_position[Y_AXIS] = y1; - go_xy(x0, current_position[Y_AXIS], feedrate); - enable_z_endstop(true); - found = false; - for (i = 0, dir_positive = true; i < nsteps_y; current_position[Y_AXIS] -= (y1 - y0) / float(nsteps_y - 1), ++ i, dir_positive = ! dir_positive) { - go_xy(dir_positive ? x1 : x0, current_position[Y_AXIS], feedrate); - if (endstop_z_hit_on_purpose()) { - found = true; - break; - } - } - update_current_position_xyz(); - if (! found) { -// SERIAL_ECHOLN("Search in Y2 - not found"); - continue; - } -// SERIAL_ECHOLN("Search in Y2 - found"); - b = current_position[Y_AXIS]; - current_position[Y_AXIS] = 0.5f * (a + b); - - // Search in the X direction along a cross. - found = false; - enable_z_endstop(false); - go_xy(x0, current_position[Y_AXIS], feedrate); - enable_z_endstop(true); - go_xy(x1, current_position[Y_AXIS], feedrate); - update_current_position_xyz(); - if (! endstop_z_hit_on_purpose()) { -// SERIAL_ECHOLN("Search X span 0 - not found"); - continue; - } -// SERIAL_ECHOLN("Search X span 0 - found"); - a = current_position[X_AXIS]; - enable_z_endstop(false); - go_xy(x1, current_position[Y_AXIS], feedrate); - enable_z_endstop(true); - go_xy(x0, current_position[Y_AXIS], feedrate); - update_current_position_xyz(); - if (! endstop_z_hit_on_purpose()) { -// SERIAL_ECHOLN("Search X span 1 - not found"); - continue; - } -// SERIAL_ECHOLN("Search X span 1 - found"); - b = current_position[X_AXIS]; - // Go to the center. - enable_z_endstop(false); - current_position[X_AXIS] = 0.5f * (a + b); - go_xy(current_position[X_AXIS], current_position[Y_AXIS], feedrate); - found = true; - -#if 1 - // Search in the Y direction along a cross. - found = false; - enable_z_endstop(false); - go_xy(current_position[X_AXIS], y0, feedrate); - enable_z_endstop(true); - go_xy(current_position[X_AXIS], y1, feedrate); - update_current_position_xyz(); - if (! endstop_z_hit_on_purpose()) { -// SERIAL_ECHOLN("Search Y2 span 0 - not found"); - continue; - } -// SERIAL_ECHOLN("Search Y2 span 0 - found"); - a = current_position[Y_AXIS]; - enable_z_endstop(false); - go_xy(current_position[X_AXIS], y1, feedrate); - enable_z_endstop(true); - go_xy(current_position[X_AXIS], y0, feedrate); - update_current_position_xyz(); - if (! endstop_z_hit_on_purpose()) { -// SERIAL_ECHOLN("Search Y2 span 1 - not found"); - continue; - } -// SERIAL_ECHOLN("Search Y2 span 1 - found"); - b = current_position[Y_AXIS]; - // Go to the center. - enable_z_endstop(false); - current_position[Y_AXIS] = 0.5f * (a + b); - go_xy(current_position[X_AXIS], current_position[Y_AXIS], feedrate); - found = true; -#endif - break; - } - } - - enable_z_endstop(false); - return found; -} - -// Search around the current_position[X,Y,Z]. -// It is expected, that the induction sensor is switched on at the current position. -// Look around this center point by painting a star around the point. -inline bool improve_bed_induction_sensor_point() -{ - static const float search_radius = 8.f; - - bool endstops_enabled = enable_endstops(false); - bool endstop_z_enabled = enable_z_endstop(false); - bool found = false; - float feedrate = homing_feedrate[X_AXIS] / 60.f; - float center_old_x = current_position[X_AXIS]; - float center_old_y = current_position[Y_AXIS]; - float center_x = 0.f; - float center_y = 0.f; - - for (uint8_t iter = 0; iter < 4; ++ iter) { - switch (iter) { - case 0: - destination[X_AXIS] = center_old_x - search_radius * 0.707; - destination[Y_AXIS] = center_old_y - search_radius * 0.707; - break; - case 1: - destination[X_AXIS] = center_old_x + search_radius * 0.707; - destination[Y_AXIS] = center_old_y + search_radius * 0.707; - break; - case 2: - destination[X_AXIS] = center_old_x + search_radius * 0.707; - destination[Y_AXIS] = center_old_y - search_radius * 0.707; - break; - case 3: - default: - destination[X_AXIS] = center_old_x - search_radius * 0.707; - destination[Y_AXIS] = center_old_y + search_radius * 0.707; - break; - } - - // Trim the vector from center_old_[x,y] to destination[x,y] by the bed dimensions. - float vx = destination[X_AXIS] - center_old_x; - float vy = destination[Y_AXIS] - center_old_y; - float l = sqrt(vx*vx+vy*vy); - float t; - if (destination[X_AXIS] < X_MIN_POS) { - // Exiting the bed at xmin. - t = (center_x - X_MIN_POS) / l; - destination[X_AXIS] = X_MIN_POS; - destination[Y_AXIS] = center_old_y + t * vy; - } else if (destination[X_AXIS] > X_MAX_POS) { - // Exiting the bed at xmax. - t = (X_MAX_POS - center_x) / l; - destination[X_AXIS] = X_MAX_POS; - destination[Y_AXIS] = center_old_y + t * vy; - } - if (destination[Y_AXIS] < Y_MIN_POS_FOR_BED_CALIBRATION) { - // Exiting the bed at ymin. - t = (center_y - Y_MIN_POS_FOR_BED_CALIBRATION) / l; - destination[X_AXIS] = center_old_x + t * vx; - destination[Y_AXIS] = Y_MIN_POS_FOR_BED_CALIBRATION; - } else if (destination[Y_AXIS] > Y_MAX_POS) { - // Exiting the bed at xmax. - t = (Y_MAX_POS - center_y) / l; - destination[X_AXIS] = center_old_x + t * vx; - destination[Y_AXIS] = Y_MAX_POS; - } - - // Move away from the measurement point. - enable_endstops(false); - go_xy(destination[X_AXIS], destination[Y_AXIS], feedrate); - // Move towards the measurement point, until the induction sensor triggers. - enable_endstops(true); - go_xy(center_old_x, center_old_y, feedrate); - update_current_position_xyz(); -// if (! endstop_z_hit_on_purpose()) return false; - center_x += current_position[X_AXIS]; - center_y += current_position[Y_AXIS]; - } - - // Calculate the new center, move to the new center. - center_x /= 4.f; - center_y /= 4.f; - current_position[X_AXIS] = center_x; - current_position[Y_AXIS] = center_y; - enable_endstops(false); - go_xy(current_position[X_AXIS], current_position[Y_AXIS], feedrate); - - enable_endstops(endstops_enabled); - enable_z_endstop(endstop_z_enabled); - return found; -} - -static inline void debug_output_point(const char *type, const float &x, const float &y, const float &z) -{ - SERIAL_ECHOPGM("Measured "); - SERIAL_ECHORPGM(type); - SERIAL_ECHOPGM(" "); - MYSERIAL.print(x, 5); - SERIAL_ECHOPGM(", "); - MYSERIAL.print(y, 5); - SERIAL_ECHOPGM(", "); - MYSERIAL.print(z, 5); - SERIAL_ECHOLNPGM(""); -} - -// Search around the current_position[X,Y,Z]. -// It is expected, that the induction sensor is switched on at the current position. -// Look around this center point by painting a star around the point. -#define IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS (8.f) -inline bool improve_bed_induction_sensor_point2(bool lift_z_on_min_y, int8_t verbosity_level) -{ - float center_old_x = current_position[X_AXIS]; - float center_old_y = current_position[Y_AXIS]; - float a, b; - bool point_small = false; - - enable_endstops(false); - - { - float x0 = center_old_x - IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS; - float x1 = center_old_x + IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS; - if (x0 < X_MIN_POS) - x0 = X_MIN_POS; - if (x1 > X_MAX_POS) - x1 = X_MAX_POS; - - // Search in the X direction along a cross. - enable_z_endstop(false); - go_xy(x0, current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f); - enable_z_endstop(true); - go_xy(x1, current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f); - update_current_position_xyz(); - if (! endstop_z_hit_on_purpose()) { - current_position[X_AXIS] = center_old_x; - goto canceled; - } - a = current_position[X_AXIS]; - enable_z_endstop(false); - go_xy(x1, current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f); - enable_z_endstop(true); - go_xy(x0, current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f); - update_current_position_xyz(); - if (! endstop_z_hit_on_purpose()) { - current_position[X_AXIS] = center_old_x; - goto canceled; - } - b = current_position[X_AXIS]; - if (b - a < MIN_BED_SENSOR_POINT_RESPONSE_DMR) { - if (verbosity_level >= 5) { - SERIAL_ECHOPGM("Point width too small: "); - SERIAL_ECHO(b - a); - SERIAL_ECHOLNPGM(""); - } - // We force the calibration routine to move the Z axis slightly down to make the response more pronounced. - if (b - a < 0.5f * MIN_BED_SENSOR_POINT_RESPONSE_DMR) { - // Don't use the new X value. - current_position[X_AXIS] = center_old_x; - goto canceled; - } else { - // Use the new value, but force the Z axis to go a bit lower. - point_small = true; - } - } - if (verbosity_level >= 5) { - debug_output_point(PSTR("left" ), a, current_position[Y_AXIS], current_position[Z_AXIS]); - debug_output_point(PSTR("right"), b, current_position[Y_AXIS], current_position[Z_AXIS]); - } - - // Go to the center. - enable_z_endstop(false); - current_position[X_AXIS] = 0.5f * (a + b); - go_xy(current_position[X_AXIS], current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f); - } - - { - float y0 = center_old_y - IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS; - float y1 = center_old_y + IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS; - if (y0 < Y_MIN_POS_FOR_BED_CALIBRATION) - y0 = Y_MIN_POS_FOR_BED_CALIBRATION; - if (y1 > Y_MAX_POS) - y1 = Y_MAX_POS; - - // Search in the Y direction along a cross. - enable_z_endstop(false); - go_xy(current_position[X_AXIS], y0, homing_feedrate[X_AXIS] / 60.f); - if (lift_z_on_min_y) { - // The first row of points are very close to the end stop. - // Lift the sensor to disengage the trigger. This is necessary because of the sensor hysteresis. - go_xyz(current_position[X_AXIS], y0, current_position[Z_AXIS]+1.5f, homing_feedrate[Z_AXIS] / 60.f); - // and go back. - go_xyz(current_position[X_AXIS], y0, current_position[Z_AXIS], homing_feedrate[Z_AXIS] / 60.f); - } - if (lift_z_on_min_y && (READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING) == 1) { - // Already triggering before we started the move. - // Shift the trigger point slightly outwards. - // a = current_position[Y_AXIS] - 1.5f; - a = current_position[Y_AXIS]; - } else { - enable_z_endstop(true); - go_xy(current_position[X_AXIS], y1, homing_feedrate[X_AXIS] / 60.f); - update_current_position_xyz(); - if (! endstop_z_hit_on_purpose()) { - current_position[Y_AXIS] = center_old_y; - goto canceled; - } - a = current_position[Y_AXIS]; - } - enable_z_endstop(false); - go_xy(current_position[X_AXIS], y1, homing_feedrate[X_AXIS] / 60.f); - enable_z_endstop(true); - go_xy(current_position[X_AXIS], y0, homing_feedrate[X_AXIS] / 60.f); - update_current_position_xyz(); - if (! endstop_z_hit_on_purpose()) { - current_position[Y_AXIS] = center_old_y; - goto canceled; - } - b = current_position[Y_AXIS]; - if (b - a < MIN_BED_SENSOR_POINT_RESPONSE_DMR) { - // We force the calibration routine to move the Z axis slightly down to make the response more pronounced. - if (verbosity_level >= 5) { - SERIAL_ECHOPGM("Point height too small: "); - SERIAL_ECHO(b - a); - SERIAL_ECHOLNPGM(""); - } - if (b - a < 0.5f * MIN_BED_SENSOR_POINT_RESPONSE_DMR) { - // Don't use the new Y value. - current_position[Y_AXIS] = center_old_y; - goto canceled; - } else { - // Use the new value, but force the Z axis to go a bit lower. - point_small = true; - } - } - if (verbosity_level >= 5) { - debug_output_point(PSTR("top" ), current_position[X_AXIS], a, current_position[Z_AXIS]); - debug_output_point(PSTR("bottom"), current_position[X_AXIS], b, current_position[Z_AXIS]); - } - - // Go to the center. - enable_z_endstop(false); - current_position[Y_AXIS] = 0.5f * (a + b); - go_xy(current_position[X_AXIS], current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f); - } - - // If point is small but not too small, then force the Z axis to be lowered a bit, - // but use the new value. This is important when the initial position was off in one axis, - // for example if the initial calibration was shifted in the Y axis systematically. - // Then this first step will center. - return ! point_small; - -canceled: - // Go back to the center. - enable_z_endstop(false); - go_xy(current_position[X_AXIS], current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f); - return false; -} - -// Searching the front points, where one cannot move the sensor head in front of the sensor point. -// Searching in a zig-zag movement in a plane for the maximum width of the response. -// This function may set the current_position[Y_AXIS] below Y_MIN_POS, if the function succeeded. -// If this function failed, the Y coordinate will never be outside the working space. -#define IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS (4.f) -#define IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y (0.1f) -inline bool improve_bed_induction_sensor_point3(int verbosity_level) -{ - float center_old_x = current_position[X_AXIS]; - float center_old_y = current_position[Y_AXIS]; - float a, b; - bool result = true; - - // Was the sensor point detected too far in the minus Y axis? - // If yes, the center of the induction point cannot be reached by the machine. - { - float x0 = center_old_x - IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS; - float x1 = center_old_x + IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS; - float y0 = center_old_y - IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS; - float y1 = center_old_y + IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS; - float y = y0; - - if (x0 < X_MIN_POS) - x0 = X_MIN_POS; - if (x1 > X_MAX_POS) - x1 = X_MAX_POS; - if (y0 < Y_MIN_POS_FOR_BED_CALIBRATION) - y0 = Y_MIN_POS_FOR_BED_CALIBRATION; - if (y1 > Y_MAX_POS) - y1 = Y_MAX_POS; - - if (verbosity_level >= 20) { - SERIAL_ECHOPGM("Initial position: "); - SERIAL_ECHO(center_old_x); - SERIAL_ECHOPGM(", "); - SERIAL_ECHO(center_old_y); - SERIAL_ECHOLNPGM(""); - } - - // Search in the positive Y direction, until a maximum diameter is found. - // (the next diameter is smaller than the current one.) - float dmax = 0.f; - float xmax1 = 0.f; - float xmax2 = 0.f; - for (y = y0; y < y1; y += IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y) { - enable_z_endstop(false); - go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f); - enable_z_endstop(true); - go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f); - update_current_position_xyz(); - if (! endstop_z_hit_on_purpose()) { - continue; - // SERIAL_PROTOCOLPGM("Failed 1\n"); - // current_position[X_AXIS] = center_old_x; - // goto canceled; - } - a = current_position[X_AXIS]; - enable_z_endstop(false); - go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f); - enable_z_endstop(true); - go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f); - update_current_position_xyz(); - if (! endstop_z_hit_on_purpose()) { - continue; - // SERIAL_PROTOCOLPGM("Failed 2\n"); - // current_position[X_AXIS] = center_old_x; - // goto canceled; - } - b = current_position[X_AXIS]; - if (verbosity_level >= 5) { - debug_output_point(PSTR("left" ), a, current_position[Y_AXIS], current_position[Z_AXIS]); - debug_output_point(PSTR("right"), b, current_position[Y_AXIS], current_position[Z_AXIS]); - } - float d = b - a; - if (d > dmax) { - xmax1 = 0.5f * (a + b); - dmax = d; - } else if (dmax > 0.) { - y0 = y - IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y; - break; - } - } - if (dmax == 0.) { - if (verbosity_level > 0) - SERIAL_PROTOCOLPGM("failed - not found\n"); - current_position[X_AXIS] = center_old_x; - current_position[Y_AXIS] = center_old_y; - goto canceled; - } - - { - // Find the positive Y hit. This gives the extreme Y value for the search of the maximum diameter in the -Y direction. - enable_z_endstop(false); - go_xy(xmax1, y0 + IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS, homing_feedrate[X_AXIS] / 60.f); - enable_z_endstop(true); - go_xy(xmax1, max(y0 - IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS, Y_MIN_POS_FOR_BED_CALIBRATION), homing_feedrate[X_AXIS] / 60.f); - update_current_position_xyz(); - if (! endstop_z_hit_on_purpose()) { - current_position[Y_AXIS] = center_old_y; - goto canceled; - } - if (verbosity_level >= 5) - debug_output_point(PSTR("top" ), current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]); - y1 = current_position[Y_AXIS]; - } - - if (y1 <= y0) { - // Either the induction sensor is too high, or the induction sensor target is out of reach. - current_position[Y_AXIS] = center_old_y; - goto canceled; - } - - // Search in the negative Y direction, until a maximum diameter is found. - dmax = 0.f; - // if (y0 + 1.f < y1) - // y1 = y0 + 1.f; - for (y = y1; y >= y0; y -= IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y) { - enable_z_endstop(false); - go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f); - enable_z_endstop(true); - go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f); - update_current_position_xyz(); - if (! endstop_z_hit_on_purpose()) { - continue; - /* - current_position[X_AXIS] = center_old_x; - SERIAL_PROTOCOLPGM("Failed 3\n"); - goto canceled; - */ - } - a = current_position[X_AXIS]; - enable_z_endstop(false); - go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f); - enable_z_endstop(true); - go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f); - update_current_position_xyz(); - if (! endstop_z_hit_on_purpose()) { - continue; - /* - current_position[X_AXIS] = center_old_x; - SERIAL_PROTOCOLPGM("Failed 4\n"); - goto canceled; - */ - } - b = current_position[X_AXIS]; - if (verbosity_level >= 5) { - debug_output_point(PSTR("left" ), a, current_position[Y_AXIS], current_position[Z_AXIS]); - debug_output_point(PSTR("right"), b, current_position[Y_AXIS], current_position[Z_AXIS]); - } - float d = b - a; - if (d > dmax) { - xmax2 = 0.5f * (a + b); - dmax = d; - } else if (dmax > 0.) { - y1 = y + IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y; - break; - } - } - float xmax, ymax; - if (dmax == 0.f) { - // Only the hit in the positive direction found. - xmax = xmax1; - ymax = y0; - } else { - // Both positive and negative directions found. - xmax = xmax2; - ymax = 0.5f * (y0 + y1); - for (; y >= y0; y -= IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y) { - enable_z_endstop(false); - go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f); - enable_z_endstop(true); - go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f); - update_current_position_xyz(); - if (! endstop_z_hit_on_purpose()) { - continue; - /* - current_position[X_AXIS] = center_old_x; - SERIAL_PROTOCOLPGM("Failed 3\n"); - goto canceled; - */ - } - a = current_position[X_AXIS]; - enable_z_endstop(false); - go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f); - enable_z_endstop(true); - go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f); - update_current_position_xyz(); - if (! endstop_z_hit_on_purpose()) { - continue; - /* - current_position[X_AXIS] = center_old_x; - SERIAL_PROTOCOLPGM("Failed 4\n"); - goto canceled; - */ - } - b = current_position[X_AXIS]; - if (verbosity_level >= 5) { - debug_output_point(PSTR("left" ), a, current_position[Y_AXIS], current_position[Z_AXIS]); - debug_output_point(PSTR("right"), b, current_position[Y_AXIS], current_position[Z_AXIS]); - } - float d = b - a; - if (d > dmax) { - xmax = 0.5f * (a + b); - ymax = y; - dmax = d; - } - } - } - - { - // Compare the distance in the Y+ direction with the diameter in the X direction. - // Find the positive Y hit once again, this time along the Y axis going through the X point with the highest diameter. - enable_z_endstop(false); - go_xy(xmax, ymax + IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS, homing_feedrate[X_AXIS] / 60.f); - enable_z_endstop(true); - go_xy(xmax, max(ymax - IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS, Y_MIN_POS_FOR_BED_CALIBRATION), homing_feedrate[X_AXIS] / 60.f); - update_current_position_xyz(); - if (! endstop_z_hit_on_purpose()) { - current_position[Y_AXIS] = center_old_y; - goto canceled; - } - if (verbosity_level >= 5) - debug_output_point(PSTR("top" ), current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]); - if (current_position[Y_AXIS] - Y_MIN_POS_FOR_BED_CALIBRATION < 0.5f * dmax) { - // Probably not even a half circle was detected. The induction point is likely too far in the minus Y direction. - // First verify, if the measurement has been done at a sufficient height. If no, lower the Z axis a bit. - if (current_position[Y_AXIS] < ymax || dmax < 0.5f * MIN_BED_SENSOR_POINT_RESPONSE_DMR) { - if (verbosity_level >= 5) { - SERIAL_ECHOPGM("Partial point diameter too small: "); - SERIAL_ECHO(dmax); - SERIAL_ECHOLNPGM(""); - } - result = false; - } else { - // Estimate the circle radius from the maximum diameter and height: - float h = current_position[Y_AXIS] - ymax; - float r = dmax * dmax / (8.f * h) + 0.5f * h; - if (r < 0.8f * MIN_BED_SENSOR_POINT_RESPONSE_DMR) { - if (verbosity_level >= 5) { - SERIAL_ECHOPGM("Partial point estimated radius too small: "); - SERIAL_ECHO(r); - SERIAL_ECHOPGM(", dmax:"); - SERIAL_ECHO(dmax); - SERIAL_ECHOPGM(", h:"); - SERIAL_ECHO(h); - SERIAL_ECHOLNPGM(""); - } - result = false; - } else { - // The point may end up outside of the machine working space. - // That is all right as it helps to improve the accuracy of the measurement point - // due to averaging. - // For the y correction, use an average of dmax/2 and the estimated radius. - r = 0.5f * (0.5f * dmax + r); - ymax = current_position[Y_AXIS] - r; - } - } - } else { - // If the diameter of the detected spot was smaller than a minimum allowed, - // the induction sensor is probably too high. Returning false will force - // the sensor to be lowered a tiny bit. - result = xmax >= MIN_BED_SENSOR_POINT_RESPONSE_DMR; - if (y0 > Y_MIN_POS_FOR_BED_CALIBRATION + 0.2f) - // Only in case both left and right y tangents are known, use them. - // If y0 is close to the bed edge, it may not be symmetric to the right tangent. - ymax = 0.5f * ymax + 0.25f * (y0 + y1); - } - } - - // Go to the center. - enable_z_endstop(false); - current_position[X_AXIS] = xmax; - current_position[Y_AXIS] = ymax; - if (verbosity_level >= 20) { - SERIAL_ECHOPGM("Adjusted position: "); - SERIAL_ECHO(current_position[X_AXIS]); - SERIAL_ECHOPGM(", "); - SERIAL_ECHO(current_position[Y_AXIS]); - SERIAL_ECHOLNPGM(""); - } - - // Don't clamp current_position[Y_AXIS], because the out-of-reach Y coordinate may actually be true. - // Only clamp the coordinate to go. - go_xy(current_position[X_AXIS], max(Y_MIN_POS, current_position[Y_AXIS]), homing_feedrate[X_AXIS] / 60.f); - // delay_keep_alive(3000); - } - - if (result) - return true; - // otherwise clamp the Y coordinate - -canceled: - // Go back to the center. - enable_z_endstop(false); - if (current_position[Y_AXIS] < Y_MIN_POS) - current_position[Y_AXIS] = Y_MIN_POS; - go_xy(current_position[X_AXIS], current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f); - return false; -} - -// Scan the mesh bed induction points one by one by a left-right zig-zag movement, -// write the trigger coordinates to the serial line. -// Useful for visualizing the behavior of the bed induction detector. -inline void scan_bed_induction_sensor_point() -{ - float center_old_x = current_position[X_AXIS]; - float center_old_y = current_position[Y_AXIS]; - float x0 = center_old_x - IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS; - float x1 = center_old_x + IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS; - float y0 = center_old_y - IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS; - float y1 = center_old_y + IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS; - float y = y0; - - if (x0 < X_MIN_POS) - x0 = X_MIN_POS; - if (x1 > X_MAX_POS) - x1 = X_MAX_POS; - if (y0 < Y_MIN_POS_FOR_BED_CALIBRATION) - y0 = Y_MIN_POS_FOR_BED_CALIBRATION; - if (y1 > Y_MAX_POS) - y1 = Y_MAX_POS; - - for (float y = y0; y < y1; y += IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y) { - enable_z_endstop(false); - go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f); - enable_z_endstop(true); - go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f); - update_current_position_xyz(); - if (endstop_z_hit_on_purpose()) - debug_output_point(PSTR("left" ), current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]); - enable_z_endstop(false); - go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f); - enable_z_endstop(true); - go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f); - update_current_position_xyz(); - if (endstop_z_hit_on_purpose()) - debug_output_point(PSTR("right"), current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]); - } - - enable_z_endstop(false); - current_position[X_AXIS] = center_old_x; - current_position[Y_AXIS] = center_old_y; - go_xy(current_position[X_AXIS], current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f); -} - -#define MESH_BED_CALIBRATION_SHOW_LCD - -BedSkewOffsetDetectionResultType find_bed_offset_and_skew(int8_t verbosity_level) -{ - // Don't let the manage_inactivity() function remove power from the motors. - refresh_cmd_timeout(); - - // Reusing the z_values memory for the measurement cache. - // 7x7=49 floats, good for 16 (x,y,z) vectors. - float *pts = &mbl.z_values[0][0]; - float *vec_x = pts + 2 * 4; - float *vec_y = vec_x + 2; - float *cntr = vec_y + 2; - memset(pts, 0, sizeof(float) * 7 * 7); - -// SERIAL_ECHOLNPGM("find_bed_offset_and_skew verbosity level: "); -// SERIAL_ECHO(int(verbosity_level)); -// SERIAL_ECHOPGM(""); - -#ifdef MESH_BED_CALIBRATION_SHOW_LCD - uint8_t next_line; - lcd_display_message_fullscreen_P(MSG_FIND_BED_OFFSET_AND_SKEW_LINE1, next_line); - if (next_line > 3) - next_line = 3; -#endif /* MESH_BED_CALIBRATION_SHOW_LCD */ - - // Collect the rear 2x3 points. - current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; - for (int k = 0; k < 4; ++ k) { - // Don't let the manage_inactivity() function remove power from the motors. - refresh_cmd_timeout(); -#ifdef MESH_BED_CALIBRATION_SHOW_LCD - lcd_implementation_print_at(0, next_line, k+1); - lcd_printPGM(MSG_FIND_BED_OFFSET_AND_SKEW_LINE2); -#endif /* MESH_BED_CALIBRATION_SHOW_LCD */ - float *pt = pts + k * 2; - // Go up to z_initial. - go_to_current(homing_feedrate[Z_AXIS] / 60.f); - if (verbosity_level >= 20) { - // Go to Y0, wait, then go to Y-4. - current_position[Y_AXIS] = 0.f; - go_to_current(homing_feedrate[X_AXIS] / 60.f); - SERIAL_ECHOLNPGM("At Y0"); - delay_keep_alive(5000); - current_position[Y_AXIS] = Y_MIN_POS; - go_to_current(homing_feedrate[X_AXIS] / 60.f); - SERIAL_ECHOLNPGM("At Y-4"); - delay_keep_alive(5000); - } - // Go to the measurement point position. - current_position[X_AXIS] = pgm_read_float(bed_ref_points_4+k*2); - current_position[Y_AXIS] = pgm_read_float(bed_ref_points_4+k*2+1); - go_to_current(homing_feedrate[X_AXIS] / 60.f); - if (verbosity_level >= 10) - delay_keep_alive(3000); - if (! find_bed_induction_sensor_point_xy()) - return BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND; -#if 1 - if (k == 0) { - // Improve the position of the 1st row sensor points by a zig-zag movement. - find_bed_induction_sensor_point_z(); - int8_t i = 4; - for (;;) { - if (improve_bed_induction_sensor_point3(verbosity_level)) - break; - if (-- i == 0) - return BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND; - // Try to move the Z axis down a bit to increase a chance of the sensor to trigger. - current_position[Z_AXIS] -= 0.025f; - enable_endstops(false); - enable_z_endstop(false); - go_to_current(homing_feedrate[Z_AXIS]); - } - if (i == 0) - // not found - return BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND; - } -#endif - if (verbosity_level >= 10) - delay_keep_alive(3000); - // Save the detected point position and then clamp the Y coordinate, which may have been estimated - // to lie outside the machine working space. - pt[0] = current_position[X_AXIS]; - pt[1] = current_position[Y_AXIS]; - if (current_position[Y_AXIS] < Y_MIN_POS) - current_position[Y_AXIS] = Y_MIN_POS; - // Start searching for the other points at 3mm above the last point. - current_position[Z_AXIS] += 3.f; - cntr[0] += pt[0]; - cntr[1] += pt[1]; - if (verbosity_level >= 10 && k == 0) { - // Show the zero. Test, whether the Y motor skipped steps. - current_position[Y_AXIS] = MANUAL_Y_HOME_POS; - go_to_current(homing_feedrate[X_AXIS] / 60.f); - delay_keep_alive(3000); - } - } - - if (verbosity_level >= 20) { - // Test the positions. Are the positions reproducible? Now the calibration is active in the planner. - delay_keep_alive(3000); - for (int8_t mesh_point = 0; mesh_point < 4; ++ mesh_point) { - // Don't let the manage_inactivity() function remove power from the motors. - refresh_cmd_timeout(); - // Go to the measurement point. - // Use the coorrected coordinate, which is a result of find_bed_offset_and_skew(). - current_position[X_AXIS] = pts[mesh_point*2]; - current_position[Y_AXIS] = pts[mesh_point*2+1]; - go_to_current(homing_feedrate[X_AXIS]/60); - delay_keep_alive(3000); - } - } - - BedSkewOffsetDetectionResultType result = calculate_machine_skew_and_offset_LS(pts, 4, bed_ref_points_4, vec_x, vec_y, cntr, verbosity_level); - if (result >= 0) { - world2machine_update(vec_x, vec_y, cntr); - #if 1 - // Fearlessly store the calibration values into the eeprom. - eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_CENTER+0), cntr [0]); - eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_CENTER+4), cntr [1]); - eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_X +0), vec_x[0]); - eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_X +4), vec_x[1]); - eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y +0), vec_y[0]); - eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y +4), vec_y[1]); - #endif - if (verbosity_level >= 10) { - // Length of the vec_x - float l = sqrt(vec_x[0] * vec_x[0] + vec_x[1] * vec_x[1]); - SERIAL_ECHOLNPGM("X vector length:"); - MYSERIAL.println(l); - - // Length of the vec_y - l = sqrt(vec_y[0] * vec_y[0] + vec_y[1] * vec_y[1]); - SERIAL_ECHOLNPGM("Y vector length:"); - MYSERIAL.println(l); - // Zero point correction - l = sqrt(cntr[0] * cntr[0] + cntr[1] * cntr[1]); - SERIAL_ECHOLNPGM("Zero point correction:"); - MYSERIAL.println(l); - - // vec_x and vec_y shall be nearly perpendicular. - l = vec_x[0] * vec_y[0] + vec_x[1] * vec_y[1]; - SERIAL_ECHOLNPGM("Perpendicularity"); - MYSERIAL.println(fabs(l)); - SERIAL_ECHOLNPGM("Saving bed calibration vectors to EEPROM"); - } - // Correct the current_position to match the transformed coordinate system after world2machine_rotation_and_skew and world2machine_shift were set. - world2machine_update_current(); - - if (verbosity_level >= 20) { - // Test the positions. Are the positions reproducible? Now the calibration is active in the planner. - delay_keep_alive(3000); - for (int8_t mesh_point = 0; mesh_point < 9; ++ mesh_point) { - // Don't let the manage_inactivity() function remove power from the motors. - refresh_cmd_timeout(); - // Go to the measurement point. - // Use the coorrected coordinate, which is a result of find_bed_offset_and_skew(). - current_position[X_AXIS] = pgm_read_float(bed_ref_points+mesh_point*2); - current_position[Y_AXIS] = pgm_read_float(bed_ref_points+mesh_point*2+1); - go_to_current(homing_feedrate[X_AXIS]/60); - delay_keep_alive(3000); - } - } - } - - return result; -} - -BedSkewOffsetDetectionResultType improve_bed_offset_and_skew(int8_t method, int8_t verbosity_level, uint8_t &too_far_mask) -{ - // Don't let the manage_inactivity() function remove power from the motors. - refresh_cmd_timeout(); - - // Mask of the first three points. Are they too far? - too_far_mask = 0; - - // Reusing the z_values memory for the measurement cache. - // 7x7=49 floats, good for 16 (x,y,z) vectors. - float *pts = &mbl.z_values[0][0]; - float *vec_x = pts + 2 * 9; - float *vec_y = vec_x + 2; - float *cntr = vec_y + 2; - memset(pts, 0, sizeof(float) * 7 * 7); - - // Cache the current correction matrix. - world2machine_initialize(); - vec_x[0] = world2machine_rotation_and_skew[0][0]; - vec_x[1] = world2machine_rotation_and_skew[1][0]; - vec_y[0] = world2machine_rotation_and_skew[0][1]; - vec_y[1] = world2machine_rotation_and_skew[1][1]; - cntr[0] = world2machine_shift[0]; - cntr[1] = world2machine_shift[1]; - // and reset the correction matrix, so the planner will not do anything. - world2machine_reset(); - - bool endstops_enabled = enable_endstops(false); - bool endstop_z_enabled = enable_z_endstop(false); - -#ifdef MESH_BED_CALIBRATION_SHOW_LCD - uint8_t next_line; - lcd_display_message_fullscreen_P(MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1, next_line); - if (next_line > 3) - next_line = 3; -#endif /* MESH_BED_CALIBRATION_SHOW_LCD */ - - // Collect a matrix of 9x9 points. - BedSkewOffsetDetectionResultType result = BED_SKEW_OFFSET_DETECTION_PERFECT; - for (int8_t mesh_point = 0; mesh_point < 9; ++ mesh_point) { - // Don't let the manage_inactivity() function remove power from the motors. - refresh_cmd_timeout(); - // Print the decrasing ID of the measurement point. -#ifdef MESH_BED_CALIBRATION_SHOW_LCD - lcd_implementation_print_at(0, next_line, mesh_point+1); - lcd_printPGM(MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2); -#endif /* MESH_BED_CALIBRATION_SHOW_LCD */ - - // Move up. - current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; - enable_endstops(false); - enable_z_endstop(false); - go_to_current(homing_feedrate[Z_AXIS]/60); - if (verbosity_level >= 20) { - // Go to Y0, wait, then go to Y-4. - current_position[Y_AXIS] = 0.f; - go_to_current(homing_feedrate[X_AXIS] / 60.f); - SERIAL_ECHOLNPGM("At Y0"); - delay_keep_alive(5000); - current_position[Y_AXIS] = Y_MIN_POS; - go_to_current(homing_feedrate[X_AXIS] / 60.f); - SERIAL_ECHOLNPGM("At Y-4"); - delay_keep_alive(5000); - } - // Go to the measurement point. - // Use the coorrected coordinate, which is a result of find_bed_offset_and_skew(). - current_position[X_AXIS] = vec_x[0] * pgm_read_float(bed_ref_points+mesh_point*2) + vec_y[0] * pgm_read_float(bed_ref_points+mesh_point*2+1) + cntr[0]; - current_position[Y_AXIS] = vec_x[1] * pgm_read_float(bed_ref_points+mesh_point*2) + vec_y[1] * pgm_read_float(bed_ref_points+mesh_point*2+1) + cntr[1]; - // The calibration points are very close to the min Y. - if (current_position[Y_AXIS] < Y_MIN_POS_FOR_BED_CALIBRATION) - current_position[Y_AXIS] = Y_MIN_POS_FOR_BED_CALIBRATION; - go_to_current(homing_feedrate[X_AXIS]/60); - // Find its Z position by running the normal vertical search. - if (verbosity_level >= 10) - delay_keep_alive(3000); - find_bed_induction_sensor_point_z(); - if (verbosity_level >= 10) - delay_keep_alive(3000); - // Try to move the Z axis down a bit to increase a chance of the sensor to trigger. - current_position[Z_AXIS] -= 0.025f; - // Improve the point position by searching its center in a current plane. - int8_t n_errors = 3; - for (int8_t iter = 0; iter < 8; ) { - if (verbosity_level > 20) { - SERIAL_ECHOPGM("Improving bed point "); - SERIAL_ECHO(mesh_point); - SERIAL_ECHOPGM(", iteration "); - SERIAL_ECHO(iter); - SERIAL_ECHOPGM(", z"); - MYSERIAL.print(current_position[Z_AXIS], 5); - SERIAL_ECHOLNPGM(""); - } - bool found = false; - if (mesh_point < 3) { - // Because the sensor cannot move in front of the first row - // of the sensor points, the y position cannot be measured - // by a cross center method. - // Use a zig-zag search for the first row of the points. - found = improve_bed_induction_sensor_point3(verbosity_level); - } else { - switch (method) { - case 0: found = improve_bed_induction_sensor_point(); break; - case 1: found = improve_bed_induction_sensor_point2(mesh_point < 3, verbosity_level); break; - default: break; - } - } - if (found) { - if (iter > 3) { - // Average the last 4 measurements. - pts[mesh_point*2 ] += current_position[X_AXIS]; - pts[mesh_point*2+1] += current_position[Y_AXIS]; - } - if (current_position[Y_AXIS] < Y_MIN_POS) - current_position[Y_AXIS] = Y_MIN_POS; - ++ iter; - } else if (n_errors -- == 0) { - // Give up. - result = BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND; - goto canceled; - } else { - // Try to move the Z axis down a bit to increase a chance of the sensor to trigger. - current_position[Z_AXIS] -= 0.05f; - enable_endstops(false); - enable_z_endstop(false); - go_to_current(homing_feedrate[Z_AXIS]); - if (verbosity_level >= 5) { - SERIAL_ECHOPGM("Improving bed point "); - SERIAL_ECHO(mesh_point); - SERIAL_ECHOPGM(", iteration "); - SERIAL_ECHO(iter); - SERIAL_ECHOPGM(" failed. Lowering z to "); - MYSERIAL.print(current_position[Z_AXIS], 5); - SERIAL_ECHOLNPGM(""); - } - } - } - if (verbosity_level >= 10) - delay_keep_alive(3000); - } - // Don't let the manage_inactivity() function remove power from the motors. - refresh_cmd_timeout(); - - // Average the last 4 measurements. - for (int8_t i = 0; i < 18; ++ i) - pts[i] *= (1.f/4.f); - - enable_endstops(false); - enable_z_endstop(false); - - if (verbosity_level >= 5) { - // Test the positions. Are the positions reproducible? - for (int8_t mesh_point = 0; mesh_point < 9; ++ mesh_point) { - // Don't let the manage_inactivity() function remove power from the motors. - refresh_cmd_timeout(); - // Go to the measurement point. - // Use the coorrected coordinate, which is a result of find_bed_offset_and_skew(). - current_position[X_AXIS] = pts[mesh_point*2]; - current_position[Y_AXIS] = pts[mesh_point*2+1]; - if (verbosity_level >= 10) { - go_to_current(homing_feedrate[X_AXIS]/60); - delay_keep_alive(3000); - } - SERIAL_ECHOPGM("Final measured bed point "); - SERIAL_ECHO(mesh_point); - SERIAL_ECHOPGM(": "); - MYSERIAL.print(current_position[X_AXIS], 5); - SERIAL_ECHOPGM(", "); - MYSERIAL.print(current_position[Y_AXIS], 5); - SERIAL_ECHOLNPGM(""); - } - } - - { - // First fill in the too_far_mask from the measured points. - for (uint8_t mesh_point = 0; mesh_point < 3; ++ mesh_point) - if (pts[mesh_point * 2 + 1] < Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH) - too_far_mask |= 1 << mesh_point; - result = calculate_machine_skew_and_offset_LS(pts, 9, bed_ref_points, vec_x, vec_y, cntr, verbosity_level); - if (result < 0) { - SERIAL_ECHOLNPGM("Calculation of the machine skew and offset failed."); - goto canceled; - } - // In case of success, update the too_far_mask from the calculated points. - for (uint8_t mesh_point = 0; mesh_point < 3; ++ mesh_point) { - float y = vec_x[1] * pgm_read_float(bed_ref_points+mesh_point*2) + vec_y[1] * pgm_read_float(bed_ref_points+mesh_point*2+1) + cntr[1]; - if (y < Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH) - too_far_mask |= 1 << mesh_point; - } - } - - world2machine_update(vec_x, vec_y, cntr); -#if 1 - // Fearlessly store the calibration values into the eeprom. - eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_CENTER+0), cntr [0]); - eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_CENTER+4), cntr [1]); - eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_X +0), vec_x[0]); - eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_X +4), vec_x[1]); - eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y +0), vec_y[0]); - eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y +4), vec_y[1]); -#endif - - // Correct the current_position to match the transformed coordinate system after world2machine_rotation_and_skew and world2machine_shift were set. - world2machine_update_current(); - - enable_endstops(false); - enable_z_endstop(false); - - if (verbosity_level >= 5) { - // Test the positions. Are the positions reproducible? Now the calibration is active in the planner. - delay_keep_alive(3000); - for (int8_t mesh_point = 0; mesh_point < 9; ++ mesh_point) { - // Don't let the manage_inactivity() function remove power from the motors. - refresh_cmd_timeout(); - // Go to the measurement point. - // Use the coorrected coordinate, which is a result of find_bed_offset_and_skew(). - current_position[X_AXIS] = pgm_read_float(bed_ref_points+mesh_point*2); - current_position[Y_AXIS] = pgm_read_float(bed_ref_points+mesh_point*2+1); - if (verbosity_level >= 10) { - go_to_current(homing_feedrate[X_AXIS]/60); - delay_keep_alive(3000); - } - { - float x, y; - world2machine(current_position[X_AXIS], current_position[Y_AXIS], x, y); - SERIAL_ECHOPGM("Final calculated bed point "); - SERIAL_ECHO(mesh_point); - SERIAL_ECHOPGM(": "); - MYSERIAL.print(x, 5); - SERIAL_ECHOPGM(", "); - MYSERIAL.print(y, 5); - SERIAL_ECHOLNPGM(""); - } - } - } - - // Sample Z heights for the mesh bed leveling. - // In addition, store the results into an eeprom, to be used later for verification of the bed leveling process. - if (! sample_mesh_and_store_reference()) - goto canceled; - - enable_endstops(endstops_enabled); - enable_z_endstop(endstop_z_enabled); - // Don't let the manage_inactivity() function remove power from the motors. - refresh_cmd_timeout(); - return result; - -canceled: - // Don't let the manage_inactivity() function remove power from the motors. - refresh_cmd_timeout(); - // Print head up. - current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; - go_to_current(homing_feedrate[Z_AXIS]/60); - // Store the identity matrix to EEPROM. - reset_bed_offset_and_skew(); - enable_endstops(endstops_enabled); - enable_z_endstop(endstop_z_enabled); - return result; -} - -void go_home_with_z_lift() -{ - // Don't let the manage_inactivity() function remove power from the motors. - refresh_cmd_timeout(); - // Go home. - // First move up to a safe height. - current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; - go_to_current(homing_feedrate[Z_AXIS]/60); - // Second move to XY [0, 0]. - current_position[X_AXIS] = X_MIN_POS+0.2; - current_position[Y_AXIS] = Y_MIN_POS+0.2; - // Clamp to the physical coordinates. - world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]); - go_to_current(homing_feedrate[X_AXIS]/60); - // Third move up to a safe height. - current_position[Z_AXIS] = Z_MIN_POS; - go_to_current(homing_feedrate[Z_AXIS]/60); -} - -// Sample the 9 points of the bed and store them into the EEPROM as a reference. -// When calling this function, the X, Y, Z axes should be already homed, -// and the world2machine correction matrix should be active. -// Returns false if the reference values are more than 3mm far away. -bool sample_mesh_and_store_reference() -{ - bool endstops_enabled = enable_endstops(false); - bool endstop_z_enabled = enable_z_endstop(false); - - // Don't let the manage_inactivity() function remove power from the motors. - refresh_cmd_timeout(); - -#ifdef MESH_BED_CALIBRATION_SHOW_LCD - uint8_t next_line; - lcd_display_message_fullscreen_P(MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1, next_line); - if (next_line > 3) - next_line = 3; - // display "point xx of yy" - lcd_implementation_print_at(0, next_line, 1); - lcd_printPGM(MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2); -#endif /* MESH_BED_CALIBRATION_SHOW_LCD */ - - // Sample Z heights for the mesh bed leveling. - // In addition, store the results into an eeprom, to be used later for verification of the bed leveling process. - { - // The first point defines the reference. - current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; - go_to_current(homing_feedrate[Z_AXIS]/60); - current_position[X_AXIS] = pgm_read_float(bed_ref_points); - current_position[Y_AXIS] = pgm_read_float(bed_ref_points+1); - world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]); - go_to_current(homing_feedrate[X_AXIS]/60); - memcpy(destination, current_position, sizeof(destination)); - enable_endstops(true); - homeaxis(Z_AXIS); - enable_endstops(false); - find_bed_induction_sensor_point_z(); - mbl.set_z(0, 0, current_position[Z_AXIS]); - } - for (int8_t mesh_point = 1; mesh_point != MESH_MEAS_NUM_X_POINTS * MESH_MEAS_NUM_Y_POINTS; ++ mesh_point) { - // Don't let the manage_inactivity() function remove power from the motors. - refresh_cmd_timeout(); - // Print the decrasing ID of the measurement point. - current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; - go_to_current(homing_feedrate[Z_AXIS]/60); - current_position[X_AXIS] = pgm_read_float(bed_ref_points+2*mesh_point); - current_position[Y_AXIS] = pgm_read_float(bed_ref_points+2*mesh_point+1); - world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]); - go_to_current(homing_feedrate[X_AXIS]/60); -#ifdef MESH_BED_CALIBRATION_SHOW_LCD - // display "point xx of yy" - lcd_implementation_print_at(0, next_line, mesh_point+1); - lcd_printPGM(MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2); -#endif /* MESH_BED_CALIBRATION_SHOW_LCD */ - find_bed_induction_sensor_point_z(); - // Get cords of measuring point - int8_t ix = mesh_point % MESH_MEAS_NUM_X_POINTS; - int8_t iy = mesh_point / MESH_MEAS_NUM_X_POINTS; - if (iy & 1) ix = (MESH_MEAS_NUM_X_POINTS - 1) - ix; // Zig zag - mbl.set_z(ix, iy, current_position[Z_AXIS]); - } - { - // Verify the span of the Z values. - float zmin = mbl.z_values[0][0]; - float zmax = zmax; - for (int8_t j = 0; j < 3; ++ j) - for (int8_t i = 0; i < 3; ++ i) { - zmin = min(zmin, mbl.z_values[j][i]); - zmax = min(zmax, mbl.z_values[j][i]); - } - if (zmax - zmin > 3.f) { - // The span of the Z offsets is extreme. Give up. - // Homing failed on some of the points. - SERIAL_PROTOCOLLNPGM("Exreme span of the Z values!"); - return false; - } - } - - // Store the correction values to EEPROM. - // Offsets of the Z heiths of the calibration points from the first point. - // The offsets are saved as 16bit signed int, scaled to tenths of microns. - { - uint16_t addr = EEPROM_BED_CALIBRATION_Z_JITTER; - for (int8_t j = 0; j < 3; ++ j) - for (int8_t i = 0; i < 3; ++ i) { - if (i == 0 && j == 0) - continue; - float dif = mbl.z_values[j][i] - mbl.z_values[0][0]; - int16_t dif_quantized = int16_t(floor(dif * 100.f + 0.5f)); - eeprom_update_word((uint16_t*)addr, *reinterpret_cast(&dif_quantized)); - #if 0 - { - uint16_t z_offset_u = eeprom_read_word((uint16_t*)addr); - float dif2 = *reinterpret_cast(&z_offset_u) * 0.01; - - SERIAL_ECHOPGM("Bed point "); - SERIAL_ECHO(i); - SERIAL_ECHOPGM(","); - SERIAL_ECHO(j); - SERIAL_ECHOPGM(", differences: written "); - MYSERIAL.print(dif, 5); - SERIAL_ECHOPGM(", read: "); - MYSERIAL.print(dif2, 5); - SERIAL_ECHOLNPGM(""); - } - #endif - addr += 2; - } - } - - mbl.upsample_3x3(); - mbl.active = true; - - go_home_with_z_lift(); - - enable_endstops(endstops_enabled); - enable_z_endstop(endstop_z_enabled); - return true; -} - -bool scan_bed_induction_points(int8_t verbosity_level) -{ - // Don't let the manage_inactivity() function remove power from the motors. - refresh_cmd_timeout(); - - // Reusing the z_values memory for the measurement cache. - // 7x7=49 floats, good for 16 (x,y,z) vectors. - float *pts = &mbl.z_values[0][0]; - float *vec_x = pts + 2 * 9; - float *vec_y = vec_x + 2; - float *cntr = vec_y + 2; - memset(pts, 0, sizeof(float) * 7 * 7); - - // Cache the current correction matrix. - world2machine_initialize(); - vec_x[0] = world2machine_rotation_and_skew[0][0]; - vec_x[1] = world2machine_rotation_and_skew[1][0]; - vec_y[0] = world2machine_rotation_and_skew[0][1]; - vec_y[1] = world2machine_rotation_and_skew[1][1]; - cntr[0] = world2machine_shift[0]; - cntr[1] = world2machine_shift[1]; - // and reset the correction matrix, so the planner will not do anything. - world2machine_reset(); - - bool endstops_enabled = enable_endstops(false); - bool endstop_z_enabled = enable_z_endstop(false); - - // Collect a matrix of 9x9 points. - for (int8_t mesh_point = 0; mesh_point < 9; ++ mesh_point) { - // Don't let the manage_inactivity() function remove power from the motors. - refresh_cmd_timeout(); - - // Move up. - current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; - enable_endstops(false); - enable_z_endstop(false); - go_to_current(homing_feedrate[Z_AXIS]/60); - // Go to the measurement point. - // Use the coorrected coordinate, which is a result of find_bed_offset_and_skew(). - current_position[X_AXIS] = vec_x[0] * pgm_read_float(bed_ref_points+mesh_point*2) + vec_y[0] * pgm_read_float(bed_ref_points+mesh_point*2+1) + cntr[0]; - current_position[Y_AXIS] = vec_x[1] * pgm_read_float(bed_ref_points+mesh_point*2) + vec_y[1] * pgm_read_float(bed_ref_points+mesh_point*2+1) + cntr[1]; - // The calibration points are very close to the min Y. - if (current_position[Y_AXIS] < Y_MIN_POS_FOR_BED_CALIBRATION) - current_position[Y_AXIS] = Y_MIN_POS_FOR_BED_CALIBRATION; - go_to_current(homing_feedrate[X_AXIS]/60); - find_bed_induction_sensor_point_z(); - scan_bed_induction_sensor_point(); - } - // Don't let the manage_inactivity() function remove power from the motors. - refresh_cmd_timeout(); - - enable_endstops(false); - enable_z_endstop(false); - - // Don't let the manage_inactivity() function remove power from the motors. - refresh_cmd_timeout(); - - enable_endstops(endstops_enabled); - enable_z_endstop(endstop_z_enabled); - return true; -} - -// Shift a Z axis by a given delta. -// To replace loading of the babystep correction. -static void shift_z(float delta) -{ - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] - delta, current_position[E_AXIS], homing_feedrate[Z_AXIS]/40, active_extruder); - st_synchronize(); - plan_set_z_position(current_position[Z_AXIS]); -} - -#define BABYSTEP_LOADZ_BY_PLANNER - -// Number of baby steps applied -static int babystepLoadZ = 0; - -void babystep_apply() -{ - // Apply Z height correction aka baby stepping before mesh bed leveling gets activated. - if(calibration_status() == CALIBRATION_STATUS_CALIBRATED) - { - check_babystep(); //checking if babystep is in allowed range, otherwise setting babystep to 0 - - // End of G80: Apply the baby stepping value. - EEPROM_read_B(EEPROM_BABYSTEP_Z,&babystepLoadZ); - - #if 0 - SERIAL_ECHO("Z baby step: "); - SERIAL_ECHO(babystepLoadZ); - SERIAL_ECHO(", current Z: "); - SERIAL_ECHO(current_position[Z_AXIS]); - SERIAL_ECHO("correction: "); - SERIAL_ECHO(float(babystepLoadZ) / float(axis_steps_per_unit[Z_AXIS])); - SERIAL_ECHOLN(""); - #endif - #ifdef BABYSTEP_LOADZ_BY_PLANNER - shift_z(- float(babystepLoadZ) / float(axis_steps_per_unit[Z_AXIS])); - #else - babystepsTodoZadd(babystepLoadZ); - #endif /* BABYSTEP_LOADZ_BY_PLANNER */ - } -} - -void babystep_undo() -{ -#ifdef BABYSTEP_LOADZ_BY_PLANNER - shift_z(float(babystepLoadZ) / float(axis_steps_per_unit[Z_AXIS])); -#else - babystepsTodoZsubtract(babystepLoadZ); -#endif /* BABYSTEP_LOADZ_BY_PLANNER */ - babystepLoadZ = 0; -} - -void babystep_reset() -{ - babystepLoadZ = 0; -} \ No newline at end of file +#include "Marlin.h" +#include "Configuration.h" +#include "ConfigurationStore.h" +#include "language_all.h" +#include "mesh_bed_calibration.h" +#include "mesh_bed_leveling.h" +#include "stepper.h" +#include "ultralcd.h" + +uint8_t world2machine_correction_mode; +float world2machine_rotation_and_skew[2][2]; +float world2machine_rotation_and_skew_inv[2][2]; +float world2machine_shift[2]; + +// Weight of the Y coordinate for the least squares fitting of the bed induction sensor targets. +// Only used for the first row of the points, which may not befully in reach of the sensor. +#define WEIGHT_FIRST_ROW_X_HIGH (1.f) +#define WEIGHT_FIRST_ROW_X_LOW (0.35f) +#define WEIGHT_FIRST_ROW_Y_HIGH (0.3f) +#define WEIGHT_FIRST_ROW_Y_LOW (0.0f) + +#define BED_ZERO_REF_X (- 22.f + X_PROBE_OFFSET_FROM_EXTRUDER) +#define BED_ZERO_REF_Y (- 0.6f + Y_PROBE_OFFSET_FROM_EXTRUDER) + +// Scaling of the real machine axes against the programmed dimensions in the firmware. +// The correction is tiny, here around 0.5mm on 250mm length. +//#define MACHINE_AXIS_SCALE_X ((250.f - 0.5f) / 250.f) +//#define MACHINE_AXIS_SCALE_Y ((250.f - 0.5f) / 250.f) +#define MACHINE_AXIS_SCALE_X 1.f +#define MACHINE_AXIS_SCALE_Y 1.f + +#define BED_CALIBRATION_POINT_OFFSET_MAX_EUCLIDIAN (0.8f) +#define BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_X (0.8f) +#define BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_Y (1.5f) + +#define MIN_BED_SENSOR_POINT_RESPONSE_DMR (2.0f) + +//#define Y_MIN_POS_FOR_BED_CALIBRATION (MANUAL_Y_HOME_POS-0.2f) +#define Y_MIN_POS_FOR_BED_CALIBRATION (Y_MIN_POS) +// Distances toward the print bed edge may not be accurate. +#define Y_MIN_POS_CALIBRATION_POINT_ACCURATE (Y_MIN_POS + 3.f) +// When the measured point center is out of reach of the sensor, Y coordinate will be ignored +// by the Least Squares fitting and the X coordinate will be weighted low. +#define Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH (Y_MIN_POS - 0.5f) + +// 0.12 degrees equals to an offset of 0.5mm on 250mm length. +const float bed_skew_angle_mild = (0.12f * M_PI / 180.f); +// 0.25 degrees equals to an offset of 1.1mm on 250mm length. +const float bed_skew_angle_extreme = (0.25f * M_PI / 180.f); + +// Positions of the bed reference points in the machine coordinates, referenced to the P.I.N.D.A sensor. +// The points are ordered in a zig-zag fashion to speed up the calibration. +const float bed_ref_points[] PROGMEM = { + 13.f - BED_ZERO_REF_X, 6.4f - BED_ZERO_REF_Y, + 115.f - BED_ZERO_REF_X, 6.4f - BED_ZERO_REF_Y, + 216.f - BED_ZERO_REF_X, 6.4f - BED_ZERO_REF_Y, + + 216.f - BED_ZERO_REF_X, 104.4f - BED_ZERO_REF_Y, + 115.f - BED_ZERO_REF_X, 104.4f - BED_ZERO_REF_Y, + 13.f - BED_ZERO_REF_X, 104.4f - BED_ZERO_REF_Y, + + 13.f - BED_ZERO_REF_X, 202.4f - BED_ZERO_REF_Y, + 115.f - BED_ZERO_REF_X, 202.4f - BED_ZERO_REF_Y, + 216.f - BED_ZERO_REF_X, 202.4f - BED_ZERO_REF_Y +}; + +// Positions of the bed reference points in the machine coordinates, referenced to the P.I.N.D.A sensor. +// The points are the following: center front, center right, center rear, center left. +const float bed_ref_points_4[] PROGMEM = { + 115.f - BED_ZERO_REF_X, 6.4f - BED_ZERO_REF_Y, + 216.f - BED_ZERO_REF_X, 104.4f - BED_ZERO_REF_Y, + 115.f - BED_ZERO_REF_X, 202.4f - BED_ZERO_REF_Y, + 13.f - BED_ZERO_REF_X, 104.4f - BED_ZERO_REF_Y +}; + +static inline float sqr(float x) { return x * x; } + +static inline bool point_on_1st_row(const uint8_t i, const uint8_t npts) +{ + if (npts == 4) return (i == 0); + else return (i < 3); +} + +// Weight of a point coordinate in a least squares optimization. +// The first row of points may not be fully reachable +// and the y values may be shortened a bit by the bed carriage +// pulling the belt up. +static inline float point_weight_x(const uint8_t i, const uint8_t npts, const float &y) +{ + float w = 1.f; + if (point_on_1st_row(i, npts)) { + if (y >= Y_MIN_POS_CALIBRATION_POINT_ACCURATE) { + w = WEIGHT_FIRST_ROW_X_HIGH; + } else if (y < Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH) { + // If the point is fully outside, give it some weight. + w = WEIGHT_FIRST_ROW_X_LOW; + } else { + // Linearly interpolate the weight from 1 to WEIGHT_FIRST_ROW_X. + float t = (y - Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH) / (Y_MIN_POS_CALIBRATION_POINT_ACCURATE - Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH); + w = (1.f - t) * WEIGHT_FIRST_ROW_X_LOW + t * WEIGHT_FIRST_ROW_X_HIGH; + } + } + return w; +} + +// Weight of a point coordinate in a least squares optimization. +// The first row of points may not be fully reachable +// and the y values may be shortened a bit by the bed carriage +// pulling the belt up. +static inline float point_weight_y(const uint8_t i, const uint8_t npts, const float &y) +{ + float w = 1.f; + if (point_on_1st_row(i, npts)) { + if (y >= Y_MIN_POS_CALIBRATION_POINT_ACCURATE) { + w = WEIGHT_FIRST_ROW_Y_HIGH; + } else if (y < Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH) { + // If the point is fully outside, give it some weight. + w = WEIGHT_FIRST_ROW_Y_LOW; + } else { + // Linearly interpolate the weight from 1 to WEIGHT_FIRST_ROW_X. + float t = (y - Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH) / (Y_MIN_POS_CALIBRATION_POINT_ACCURATE - Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH); + w = (1.f - t) * WEIGHT_FIRST_ROW_Y_LOW + t * WEIGHT_FIRST_ROW_Y_HIGH; + } + } + return w; +} + +// Non-Linear Least Squares fitting of the bed to the measured induction points +// using the Gauss-Newton method. +// This method will maintain a unity length of the machine axes, +// which is the correct approach if the sensor points are not measured precisely. +BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS( + // Matrix of maximum 9 2D points (18 floats) + const float *measured_pts, + uint8_t npts, + const float *true_pts, + // Resulting correction matrix. + float *vec_x, + float *vec_y, + float *cntr, + // Temporary values, 49-18-(2*3)=25 floats + // , float *temp + int8_t verbosity_level + ) +{ + if (verbosity_level >= 10) { + SERIAL_ECHOLNPGM("calculate machine skew and offset LS"); + + // Show the initial state, before the fitting. + SERIAL_ECHOPGM("X vector, initial: "); + MYSERIAL.print(vec_x[0], 5); + SERIAL_ECHOPGM(", "); + MYSERIAL.print(vec_x[1], 5); + SERIAL_ECHOLNPGM(""); + + SERIAL_ECHOPGM("Y vector, initial: "); + MYSERIAL.print(vec_y[0], 5); + SERIAL_ECHOPGM(", "); + MYSERIAL.print(vec_y[1], 5); + SERIAL_ECHOLNPGM(""); + + SERIAL_ECHOPGM("center, initial: "); + MYSERIAL.print(cntr[0], 5); + SERIAL_ECHOPGM(", "); + MYSERIAL.print(cntr[1], 5); + SERIAL_ECHOLNPGM(""); + + for (uint8_t i = 0; i < npts; ++i) { + SERIAL_ECHOPGM("point #"); + MYSERIAL.print(int(i)); + SERIAL_ECHOPGM(" measured: ("); + MYSERIAL.print(measured_pts[i * 2], 5); + SERIAL_ECHOPGM(", "); + MYSERIAL.print(measured_pts[i * 2 + 1], 5); + SERIAL_ECHOPGM("); target: ("); + MYSERIAL.print(pgm_read_float(true_pts + i * 2), 5); + SERIAL_ECHOPGM(", "); + MYSERIAL.print(pgm_read_float(true_pts + i * 2 + 1), 5); + SERIAL_ECHOPGM("), error: "); + MYSERIAL.print(sqrt( + sqr(pgm_read_float(true_pts + i * 2) - measured_pts[i * 2]) + + sqr(pgm_read_float(true_pts + i * 2 + 1) - measured_pts[i * 2 + 1])), 5); + SERIAL_ECHOLNPGM(""); + } + delay_keep_alive(100); + } + + // Run some iterations of the Gauss-Newton method of non-linear least squares. + // Initial set of parameters: + // X,Y offset + cntr[0] = 0.f; + cntr[1] = 0.f; + // Rotation of the machine X axis from the bed X axis. + float a1 = 0; + // Rotation of the machine Y axis from the bed Y axis. + float a2 = 0; + for (int8_t iter = 0; iter < 100; ++iter) { + float c1 = cos(a1) * MACHINE_AXIS_SCALE_X; + float s1 = sin(a1) * MACHINE_AXIS_SCALE_X; + float c2 = cos(a2) * MACHINE_AXIS_SCALE_Y; + float s2 = sin(a2) * MACHINE_AXIS_SCALE_Y; + // Prepare the Normal equation for the Gauss-Newton method. + float A[4][4] = { 0.f }; + float b[4] = { 0.f }; + float acc; + for (uint8_t r = 0; r < 4; ++r) { + for (uint8_t c = 0; c < 4; ++c) { + acc = 0; + // J^T times J + for (uint8_t i = 0; i < npts; ++i) { + // First for the residuum in the x axis: + if (r != 1 && c != 1) { + float a = + (r == 0) ? 1.f : + ((r == 2) ? (-s1 * measured_pts[2 * i]) : + (-c2 * measured_pts[2 * i + 1])); + float b = + (c == 0) ? 1.f : + ((c == 2) ? (-s1 * measured_pts[2 * i]) : + (-c2 * measured_pts[2 * i + 1])); + float w = point_weight_x(i, npts, measured_pts[2 * i + 1]); + acc += a * b * w; + } + // Second for the residuum in the y axis. + // The first row of the points have a low weight, because their position may not be known + // with a sufficient accuracy. + if (r != 0 && c != 0) { + float a = + (r == 1) ? 1.f : + ((r == 2) ? ( c1 * measured_pts[2 * i]) : + (-s2 * measured_pts[2 * i + 1])); + float b = + (c == 1) ? 1.f : + ((c == 2) ? ( c1 * measured_pts[2 * i]) : + (-s2 * measured_pts[2 * i + 1])); + float w = point_weight_y(i, npts, measured_pts[2 * i + 1]); + acc += a * b * w; + } + } + A[r][c] = acc; + } + // J^T times f(x) + acc = 0.f; + for (uint8_t i = 0; i < npts; ++i) { + { + float j = + (r == 0) ? 1.f : + ((r == 1) ? 0.f : + ((r == 2) ? (-s1 * measured_pts[2 * i]) : + (-c2 * measured_pts[2 * i + 1]))); + float fx = c1 * measured_pts[2 * i] - s2 * measured_pts[2 * i + 1] + cntr[0] - pgm_read_float(true_pts + i * 2); + float w = point_weight_x(i, npts, measured_pts[2 * i + 1]); + acc += j * fx * w; + } + { + float j = + (r == 0) ? 0.f : + ((r == 1) ? 1.f : + ((r == 2) ? ( c1 * measured_pts[2 * i]) : + (-s2 * measured_pts[2 * i + 1]))); + float fy = s1 * measured_pts[2 * i] + c2 * measured_pts[2 * i + 1] + cntr[1] - pgm_read_float(true_pts + i * 2 + 1); + float w = point_weight_y(i, npts, measured_pts[2 * i + 1]); + acc += j * fy * w; + } + } + b[r] = -acc; + } + + // Solve for h by a Gauss iteration method. + float h[4] = { 0.f }; + for (uint8_t gauss_iter = 0; gauss_iter < 100; ++gauss_iter) { + h[0] = (b[0] - A[0][1] * h[1] - A[0][2] * h[2] - A[0][3] * h[3]) / A[0][0]; + h[1] = (b[1] - A[1][0] * h[0] - A[1][2] * h[2] - A[1][3] * h[3]) / A[1][1]; + h[2] = (b[2] - A[2][0] * h[0] - A[2][1] * h[1] - A[2][3] * h[3]) / A[2][2]; + h[3] = (b[3] - A[3][0] * h[0] - A[3][1] * h[1] - A[3][2] * h[2]) / A[3][3]; + } + + // and update the current position with h. + // It may be better to use the Levenberg-Marquart method here, + // but because we are very close to the solution alread, + // the simple Gauss-Newton non-linear Least Squares method works well enough. + cntr[0] += h[0]; + cntr[1] += h[1]; + a1 += h[2]; + a2 += h[3]; + + if (verbosity_level >= 20) { + SERIAL_ECHOPGM("iteration: "); + MYSERIAL.print(int(iter)); + SERIAL_ECHOPGM("; correction vector: "); + MYSERIAL.print(h[0], 5); + SERIAL_ECHOPGM(", "); + MYSERIAL.print(h[1], 5); + SERIAL_ECHOPGM(", "); + MYSERIAL.print(h[2], 5); + SERIAL_ECHOPGM(", "); + MYSERIAL.print(h[3], 5); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("corrected x/y: "); + MYSERIAL.print(cntr[0], 5); + SERIAL_ECHOPGM(", "); + MYSERIAL.print(cntr[0], 5); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("corrected angles: "); + MYSERIAL.print(180.f * a1 / M_PI, 5); + SERIAL_ECHOPGM(", "); + MYSERIAL.print(180.f * a2 / M_PI, 5); + SERIAL_ECHOLNPGM(""); + } + } + + vec_x[0] = cos(a1) * MACHINE_AXIS_SCALE_X; + vec_x[1] = sin(a1) * MACHINE_AXIS_SCALE_X; + vec_y[0] = -sin(a2) * MACHINE_AXIS_SCALE_Y; + vec_y[1] = cos(a2) * MACHINE_AXIS_SCALE_Y; + + BedSkewOffsetDetectionResultType result = BED_SKEW_OFFSET_DETECTION_PERFECT; + { + angleDiff = fabs(a2 - a1); + if (angleDiff > bed_skew_angle_mild) + result = (angleDiff > bed_skew_angle_extreme) ? + BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME : + BED_SKEW_OFFSET_DETECTION_SKEW_MILD; + if (fabs(a1) > bed_skew_angle_extreme || + fabs(a2) > bed_skew_angle_extreme) + result = BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME; + } + + if (verbosity_level >= 1) { + SERIAL_ECHOPGM("correction angles: "); + MYSERIAL.print(180.f * a1 / M_PI, 5); + SERIAL_ECHOPGM(", "); + MYSERIAL.print(180.f * a2 / M_PI, 5); + SERIAL_ECHOLNPGM(""); + } + + if (verbosity_level >= 10) { + // Show the adjusted state, before the fitting. + SERIAL_ECHOPGM("X vector new, inverted: "); + MYSERIAL.print(vec_x[0], 5); + SERIAL_ECHOPGM(", "); + MYSERIAL.print(vec_x[1], 5); + SERIAL_ECHOLNPGM(""); + + SERIAL_ECHOPGM("Y vector new, inverted: "); + MYSERIAL.print(vec_y[0], 5); + SERIAL_ECHOPGM(", "); + MYSERIAL.print(vec_y[1], 5); + SERIAL_ECHOLNPGM(""); + + SERIAL_ECHOPGM("center new, inverted: "); + MYSERIAL.print(cntr[0], 5); + SERIAL_ECHOPGM(", "); + MYSERIAL.print(cntr[1], 5); + SERIAL_ECHOLNPGM(""); + delay_keep_alive(100); + + SERIAL_ECHOLNPGM("Error after correction: "); + } + + // Measure the error after correction. + for (uint8_t i = 0; i < npts; ++i) { + float x = vec_x[0] * measured_pts[i * 2] + vec_y[0] * measured_pts[i * 2 + 1] + cntr[0]; + float y = vec_x[1] * measured_pts[i * 2] + vec_y[1] * measured_pts[i * 2 + 1] + cntr[1]; + float errX = sqr(pgm_read_float(true_pts + i * 2) - x); + float errY = sqr(pgm_read_float(true_pts + i * 2 + 1) - y); + float err = sqrt(errX + errY); + if (verbosity_level >= 10) { + SERIAL_ECHOPGM("point #"); + MYSERIAL.print(int(i)); + SERIAL_ECHOLNPGM(":"); + } + + if (point_on_1st_row(i, npts)) { + if(verbosity_level >= 20) SERIAL_ECHOPGM("Point on first row"); + float w = point_weight_y(i, npts, measured_pts[2 * i + 1]); + if (sqrt(errX) > BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_X || + (w != 0.f && sqrt(errY) > BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_Y)) { + result = BED_SKEW_OFFSET_DETECTION_FITTING_FAILED; + if (verbosity_level >= 20) { + SERIAL_ECHOPGM(", weigth Y: "); + MYSERIAL.print(w); + if (sqrt(errX) > BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_X) SERIAL_ECHOPGM(", error X > max. error X"); + if (w != 0.f && sqrt(errY) > BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_Y) SERIAL_ECHOPGM(", error Y > max. error Y"); + } + } + } + else { + if(verbosity_level >=20 ) SERIAL_ECHOPGM("Point not on first row"); + if (err > BED_CALIBRATION_POINT_OFFSET_MAX_EUCLIDIAN) { + result = BED_SKEW_OFFSET_DETECTION_FITTING_FAILED; + if(verbosity_level >= 20) SERIAL_ECHOPGM(", error > max. error euclidian"); + } + } + if (verbosity_level >= 10) { + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("measured: ("); + MYSERIAL.print(measured_pts[i * 2], 5); + SERIAL_ECHOPGM(", "); + MYSERIAL.print(measured_pts[i * 2 + 1], 5); + SERIAL_ECHOPGM("); corrected: ("); + MYSERIAL.print(x, 5); + SERIAL_ECHOPGM(", "); + MYSERIAL.print(y, 5); + SERIAL_ECHOPGM("); target: ("); + MYSERIAL.print(pgm_read_float(true_pts + i * 2), 5); + SERIAL_ECHOPGM(", "); + MYSERIAL.print(pgm_read_float(true_pts + i * 2 + 1), 5); + SERIAL_ECHOLNPGM(")"); + SERIAL_ECHOPGM("error: "); + MYSERIAL.print(err); + SERIAL_ECHOPGM(", error X: "); + MYSERIAL.print(sqrt(errX)); + SERIAL_ECHOPGM(", error Y: "); + MYSERIAL.print(sqrt(errY)); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOLNPGM(""); + } + } + if (verbosity_level >= 20) { + SERIAL_ECHOLNPGM("Max. errors:"); + SERIAL_ECHOPGM("Max. error X:"); + MYSERIAL.println(BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_X); + SERIAL_ECHOPGM("Max. error Y:"); + MYSERIAL.println(BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_Y); + SERIAL_ECHOPGM("Max. error euclidian:"); + MYSERIAL.println(BED_CALIBRATION_POINT_OFFSET_MAX_EUCLIDIAN); + SERIAL_ECHOLNPGM(""); + } + + #if 0 + if (result == BED_SKEW_OFFSET_DETECTION_PERFECT && fabs(a1) < bed_skew_angle_mild && fabs(a2) < bed_skew_angle_mild) { + if (verbosity_level > 0) + SERIAL_ECHOLNPGM("Very little skew detected. Disabling skew correction."); + // Just disable the skew correction. + vec_x[0] = MACHINE_AXIS_SCALE_X; + vec_x[1] = 0.f; + vec_y[0] = 0.f; + vec_y[1] = MACHINE_AXIS_SCALE_Y; + } + #else + if (result == BED_SKEW_OFFSET_DETECTION_PERFECT) { + if (verbosity_level > 0) + SERIAL_ECHOLNPGM("Very little skew detected. Orthogonalizing the axes."); + // Orthogonalize the axes. + a1 = 0.5f * (a1 + a2); + vec_x[0] = cos(a1) * MACHINE_AXIS_SCALE_X; + vec_x[1] = sin(a1) * MACHINE_AXIS_SCALE_X; + vec_y[0] = -sin(a1) * MACHINE_AXIS_SCALE_Y; + vec_y[1] = cos(a1) * MACHINE_AXIS_SCALE_Y; + // Refresh the offset. + cntr[0] = 0.f; + cntr[1] = 0.f; + float wx = 0.f; + float wy = 0.f; + for (int8_t i = 0; i < npts; ++ i) { + float x = vec_x[0] * measured_pts[i * 2] + vec_y[0] * measured_pts[i * 2 + 1]; + float y = vec_x[1] * measured_pts[i * 2] + vec_y[1] * measured_pts[i * 2 + 1]; + float w = point_weight_x(i, npts, y); + cntr[0] += w * (pgm_read_float(true_pts + i * 2) - x); + wx += w; + if (verbosity_level >= 20) { + MYSERIAL.print(i); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOLNPGM("Weight_x:"); + MYSERIAL.print(w); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOLNPGM("cntr[0]:"); + MYSERIAL.print(cntr[0]); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOLNPGM("wx:"); + MYSERIAL.print(wx); + } + w = point_weight_y(i, npts, y); + cntr[1] += w * (pgm_read_float(true_pts + i * 2 + 1) - y); + wy += w; + + if (verbosity_level >= 20) { + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOLNPGM("Weight_y:"); + MYSERIAL.print(w); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOLNPGM("cntr[1]:"); + MYSERIAL.print(cntr[1]); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOLNPGM("wy:"); + MYSERIAL.print(wy); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOLNPGM(""); + } + } + cntr[0] /= wx; + cntr[1] /= wy; + if (verbosity_level >= 20) { + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOLNPGM("Final cntr values:"); + SERIAL_ECHOLNPGM("cntr[0]:"); + MYSERIAL.print(cntr[0]); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOLNPGM("cntr[1]:"); + MYSERIAL.print(cntr[1]); + SERIAL_ECHOLNPGM(""); + } + + } + #endif + + // Invert the transformation matrix made of vec_x, vec_y and cntr. + { + float d = vec_x[0] * vec_y[1] - vec_x[1] * vec_y[0]; + float Ainv[2][2] = { + { vec_y[1] / d, -vec_y[0] / d }, + { -vec_x[1] / d, vec_x[0] / d } + }; + float cntrInv[2] = { + -Ainv[0][0] * cntr[0] - Ainv[0][1] * cntr[1], + -Ainv[1][0] * cntr[0] - Ainv[1][1] * cntr[1] + }; + vec_x[0] = Ainv[0][0]; + vec_x[1] = Ainv[1][0]; + vec_y[0] = Ainv[0][1]; + vec_y[1] = Ainv[1][1]; + cntr[0] = cntrInv[0]; + cntr[1] = cntrInv[1]; + } + + if (verbosity_level >= 1) { + // Show the adjusted state, before the fitting. + SERIAL_ECHOPGM("X vector, adjusted: "); + MYSERIAL.print(vec_x[0], 5); + SERIAL_ECHOPGM(", "); + MYSERIAL.print(vec_x[1], 5); + SERIAL_ECHOLNPGM(""); + + SERIAL_ECHOPGM("Y vector, adjusted: "); + MYSERIAL.print(vec_y[0], 5); + SERIAL_ECHOPGM(", "); + MYSERIAL.print(vec_y[1], 5); + SERIAL_ECHOLNPGM(""); + + SERIAL_ECHOPGM("center, adjusted: "); + MYSERIAL.print(cntr[0], 5); + SERIAL_ECHOPGM(", "); + MYSERIAL.print(cntr[1], 5); + SERIAL_ECHOLNPGM(""); + delay_keep_alive(100); + } + + if (verbosity_level >= 2) { + SERIAL_ECHOLNPGM("Difference after correction: "); + for (uint8_t i = 0; i < npts; ++i) { + float x = vec_x[0] * pgm_read_float(true_pts + i * 2) + vec_y[0] * pgm_read_float(true_pts + i * 2 + 1) + cntr[0]; + float y = vec_x[1] * pgm_read_float(true_pts + i * 2) + vec_y[1] * pgm_read_float(true_pts + i * 2 + 1) + cntr[1]; + SERIAL_ECHOPGM("point #"); + MYSERIAL.print(int(i)); + SERIAL_ECHOPGM("measured: ("); + MYSERIAL.print(measured_pts[i * 2], 5); + SERIAL_ECHOPGM(", "); + MYSERIAL.print(measured_pts[i * 2 + 1], 5); + SERIAL_ECHOPGM("); measured-corrected: ("); + MYSERIAL.print(x, 5); + SERIAL_ECHOPGM(", "); + MYSERIAL.print(y, 5); + SERIAL_ECHOPGM("); target: ("); + MYSERIAL.print(pgm_read_float(true_pts + i * 2), 5); + SERIAL_ECHOPGM(", "); + MYSERIAL.print(pgm_read_float(true_pts + i * 2 + 1), 5); + SERIAL_ECHOPGM("), error: "); + MYSERIAL.print(sqrt(sqr(measured_pts[i * 2] - x) + sqr(measured_pts[i * 2 + 1] - y))); + SERIAL_ECHOLNPGM(""); + } + if (verbosity_level >= 20) { + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOLNPGM("Calculate offset and skew returning result:"); + MYSERIAL.print(int(result)); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOLNPGM(""); + } + delay_keep_alive(100); + } + + return result; +} + +void reset_bed_offset_and_skew() +{ + eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_CENTER+0), 0x0FFFFFFFF); + eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_CENTER+4), 0x0FFFFFFFF); + eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_VEC_X +0), 0x0FFFFFFFF); + eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_VEC_X +4), 0x0FFFFFFFF); + eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_VEC_Y +0), 0x0FFFFFFFF); + eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_VEC_Y +4), 0x0FFFFFFFF); + + // Reset the 8 16bit offsets. + for (int8_t i = 0; i < 4; ++ i) + eeprom_update_dword((uint32_t*)(EEPROM_BED_CALIBRATION_Z_JITTER+i*4), 0x0FFFFFFFF); +} + +bool is_bed_z_jitter_data_valid() +// offsets of the Z heiths of the calibration points from the first point are saved as 16bit signed int, scaled to tenths of microns +{ + for (int8_t i = 0; i < 8; ++ i) + if (eeprom_read_word((uint16_t*)(EEPROM_BED_CALIBRATION_Z_JITTER+i*2)) == 0x0FFFF) + return false; + return true; +} + +static void world2machine_update(const float vec_x[2], const float vec_y[2], const float cntr[2]) +{ + world2machine_rotation_and_skew[0][0] = vec_x[0]; + world2machine_rotation_and_skew[1][0] = vec_x[1]; + world2machine_rotation_and_skew[0][1] = vec_y[0]; + world2machine_rotation_and_skew[1][1] = vec_y[1]; + world2machine_shift[0] = cntr[0]; + world2machine_shift[1] = cntr[1]; + // No correction. + world2machine_correction_mode = WORLD2MACHINE_CORRECTION_NONE; + if (world2machine_shift[0] != 0.f || world2machine_shift[1] != 0.f) + // Shift correction. + world2machine_correction_mode |= WORLD2MACHINE_CORRECTION_SHIFT; + if (world2machine_rotation_and_skew[0][0] != 1.f || world2machine_rotation_and_skew[0][1] != 0.f || + world2machine_rotation_and_skew[1][0] != 0.f || world2machine_rotation_and_skew[1][1] != 1.f) { + // Rotation & skew correction. + world2machine_correction_mode |= WORLD2MACHINE_CORRECTION_SKEW; + // Invert the world2machine matrix. + float d = world2machine_rotation_and_skew[0][0] * world2machine_rotation_and_skew[1][1] - world2machine_rotation_and_skew[1][0] * world2machine_rotation_and_skew[0][1]; + world2machine_rotation_and_skew_inv[0][0] = world2machine_rotation_and_skew[1][1] / d; + world2machine_rotation_and_skew_inv[0][1] = -world2machine_rotation_and_skew[0][1] / d; + world2machine_rotation_and_skew_inv[1][0] = -world2machine_rotation_and_skew[1][0] / d; + world2machine_rotation_and_skew_inv[1][1] = world2machine_rotation_and_skew[0][0] / d; + } else { + world2machine_rotation_and_skew_inv[0][0] = 1.f; + world2machine_rotation_and_skew_inv[0][1] = 0.f; + world2machine_rotation_and_skew_inv[1][0] = 0.f; + world2machine_rotation_and_skew_inv[1][1] = 1.f; + } +} + +void world2machine_reset() +{ + const float vx[] = { 1.f, 0.f }; + const float vy[] = { 0.f, 1.f }; + const float cntr[] = { 0.f, 0.f }; + world2machine_update(vx, vy, cntr); +} + +void world2machine_revert_to_uncorrected() +{ + if (world2machine_correction_mode != WORLD2MACHINE_CORRECTION_NONE) { + // Reset the machine correction matrix. + const float vx[] = { 1.f, 0.f }; + const float vy[] = { 0.f, 1.f }; + const float cntr[] = { 0.f, 0.f }; + world2machine_update(vx, vy, cntr); + // Wait for the motors to stop and update the current position with the absolute values. + st_synchronize(); + current_position[X_AXIS] = st_get_position_mm(X_AXIS); + current_position[Y_AXIS] = st_get_position_mm(Y_AXIS); + } +} + +static inline bool vec_undef(const float v[2]) +{ + const uint32_t *vx = (const uint32_t*)v; + return vx[0] == 0x0FFFFFFFF || vx[1] == 0x0FFFFFFFF; +} + +void world2machine_initialize() +{ + //SERIAL_ECHOLNPGM("world2machine_initialize"); + float cntr[2] = { + eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_CENTER+0)), + eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_CENTER+4)) + }; + float vec_x[2] = { + eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_X +0)), + eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_X +4)) + }; + float vec_y[2] = { + eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y +0)), + eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y +4)) + }; + + bool reset = false; + if (vec_undef(cntr) || vec_undef(vec_x) || vec_undef(vec_y)) { + SERIAL_ECHOLNPGM("Undefined bed correction matrix."); + reset = true; + } + else { + // Length of the vec_x shall be close to unity. + float l = sqrt(vec_x[0] * vec_x[0] + vec_x[1] * vec_x[1]); + if (l < 0.9 || l > 1.1) { + SERIAL_ECHOLNPGM("X vector length:"); + MYSERIAL.println(l); + SERIAL_ECHOLNPGM("Invalid bed correction matrix. Length of the X vector out of range."); + reset = true; + } + // Length of the vec_y shall be close to unity. + l = sqrt(vec_y[0] * vec_y[0] + vec_y[1] * vec_y[1]); + if (l < 0.9 || l > 1.1) { + SERIAL_ECHOLNPGM("Y vector length:"); + MYSERIAL.println(l); + SERIAL_ECHOLNPGM("Invalid bed correction matrix. Length of the Y vector out of range."); + reset = true; + } + // Correction of the zero point shall be reasonably small. + l = sqrt(cntr[0] * cntr[0] + cntr[1] * cntr[1]); + if (l > 15.f) { + SERIAL_ECHOLNPGM("Zero point correction:"); + MYSERIAL.println(l); + SERIAL_ECHOLNPGM("Invalid bed correction matrix. Shift out of range."); + reset = true; + } + // vec_x and vec_y shall be nearly perpendicular. + l = vec_x[0] * vec_y[0] + vec_x[1] * vec_y[1]; + if (fabs(l) > 0.1f) { + SERIAL_ECHOLNPGM("Invalid bed correction matrix. X/Y axes are far from being perpendicular."); + reset = true; + } + } + + if (reset) { + SERIAL_ECHOLNPGM("Invalid bed correction matrix. Resetting to identity."); + reset_bed_offset_and_skew(); + world2machine_reset(); + } else { + world2machine_update(vec_x, vec_y, cntr); + /* + SERIAL_ECHOPGM("world2machine_initialize() loaded: "); + MYSERIAL.print(world2machine_rotation_and_skew[0][0], 5); + SERIAL_ECHOPGM(", "); + MYSERIAL.print(world2machine_rotation_and_skew[0][1], 5); + SERIAL_ECHOPGM(", "); + MYSERIAL.print(world2machine_rotation_and_skew[1][0], 5); + SERIAL_ECHOPGM(", "); + MYSERIAL.print(world2machine_rotation_and_skew[1][1], 5); + SERIAL_ECHOPGM(", offset "); + MYSERIAL.print(world2machine_shift[0], 5); + SERIAL_ECHOPGM(", "); + MYSERIAL.print(world2machine_shift[1], 5); + SERIAL_ECHOLNPGM(""); + */ + } +} + +// When switching from absolute to corrected coordinates, +// this will get the absolute coordinates from the servos, +// applies the inverse world2machine transformation +// and stores the result into current_position[x,y]. +void world2machine_update_current() +{ + float x = current_position[X_AXIS] - world2machine_shift[0]; + float y = current_position[Y_AXIS] - world2machine_shift[1]; + current_position[X_AXIS] = world2machine_rotation_and_skew_inv[0][0] * x + world2machine_rotation_and_skew_inv[0][1] * y; + current_position[Y_AXIS] = world2machine_rotation_and_skew_inv[1][0] * x + world2machine_rotation_and_skew_inv[1][1] * y; +} + +static inline void go_xyz(float x, float y, float z, float fr) +{ + plan_buffer_line(x, y, z, current_position[E_AXIS], fr, active_extruder); + st_synchronize(); +} + +static inline void go_xy(float x, float y, float fr) +{ + plan_buffer_line(x, y, current_position[Z_AXIS], current_position[E_AXIS], fr, active_extruder); + st_synchronize(); +} + +static inline void go_to_current(float fr) +{ + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], fr, active_extruder); + st_synchronize(); +} + +static inline void update_current_position_xyz() +{ + current_position[X_AXIS] = st_get_position_mm(X_AXIS); + current_position[Y_AXIS] = st_get_position_mm(Y_AXIS); + current_position[Z_AXIS] = st_get_position_mm(Z_AXIS); + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); +} + +static inline void update_current_position_z() +{ + current_position[Z_AXIS] = st_get_position_mm(Z_AXIS); + plan_set_z_position(current_position[Z_AXIS]); +} + +// At the current position, find the Z stop. +inline bool find_bed_induction_sensor_point_z(float minimum_z, uint8_t n_iter, int verbosity_level) +{ + if(verbosity_level >= 10) SERIAL_ECHOLNPGM("find bed induction sensor point z"); + bool endstops_enabled = enable_endstops(true); + bool endstop_z_enabled = enable_z_endstop(false); + float z = 0.f; + endstop_z_hit_on_purpose(); + + // move down until you find the bed + current_position[Z_AXIS] = minimum_z; + go_to_current(homing_feedrate[Z_AXIS]/60); + // we have to let the planner know where we are right now as it is not where we said to go. + update_current_position_z(); + if (! endstop_z_hit_on_purpose()) + goto error; + + for (uint8_t i = 0; i < n_iter; ++ i) { + // Move up the retract distance. + current_position[Z_AXIS] += .5f; + go_to_current(homing_feedrate[Z_AXIS]/60); + // Move back down slowly to find bed. + current_position[Z_AXIS] = minimum_z; + go_to_current(homing_feedrate[Z_AXIS]/(4*60)); + // we have to let the planner know where we are right now as it is not where we said to go. + update_current_position_z(); + if (! endstop_z_hit_on_purpose()) + goto error; +// SERIAL_ECHOPGM("Bed find_bed_induction_sensor_point_z low, height: "); +// MYSERIAL.print(current_position[Z_AXIS], 5); +// SERIAL_ECHOLNPGM(""); + z += current_position[Z_AXIS]; + } + current_position[Z_AXIS] = z; + if (n_iter > 1) + current_position[Z_AXIS] /= float(n_iter); + + enable_endstops(endstops_enabled); + enable_z_endstop(endstop_z_enabled); +// SERIAL_ECHOLNPGM("find_bed_induction_sensor_point_z 3"); + return true; + +error: +// SERIAL_ECHOLNPGM("find_bed_induction_sensor_point_z 4"); + enable_endstops(endstops_enabled); + enable_z_endstop(endstop_z_enabled); + return false; +} + +// Search around the current_position[X,Y], +// look for the induction sensor response. +// Adjust the current_position[X,Y,Z] to the center of the target dot and its response Z coordinate. +#define FIND_BED_INDUCTION_SENSOR_POINT_X_RADIUS (8.f) +#define FIND_BED_INDUCTION_SENSOR_POINT_Y_RADIUS (6.f) +#define FIND_BED_INDUCTION_SENSOR_POINT_XY_STEP (1.f) +#define FIND_BED_INDUCTION_SENSOR_POINT_Z_STEP (0.2f) +inline bool find_bed_induction_sensor_point_xy(int verbosity_level) +{ + if(verbosity_level >= 10) MYSERIAL.println("find bed induction sensor point xy"); + float feedrate = homing_feedrate[X_AXIS] / 60.f; + bool found = false; + + { + float x0 = current_position[X_AXIS] - FIND_BED_INDUCTION_SENSOR_POINT_X_RADIUS; + float x1 = current_position[X_AXIS] + FIND_BED_INDUCTION_SENSOR_POINT_X_RADIUS; + float y0 = current_position[Y_AXIS] - FIND_BED_INDUCTION_SENSOR_POINT_Y_RADIUS; + float y1 = current_position[Y_AXIS] + FIND_BED_INDUCTION_SENSOR_POINT_Y_RADIUS; + uint8_t nsteps_y; + uint8_t i; + if (x0 < X_MIN_POS) { + x0 = X_MIN_POS; + if (verbosity_level >= 20) SERIAL_ECHOLNPGM("X searching radius lower than X_MIN. Clamping was done."); + } + if (x1 > X_MAX_POS) { + x1 = X_MAX_POS; + if (verbosity_level >= 20) SERIAL_ECHOLNPGM("X searching radius higher than X_MAX. Clamping was done."); + } + if (y0 < Y_MIN_POS_FOR_BED_CALIBRATION) { + y0 = Y_MIN_POS_FOR_BED_CALIBRATION; + if (verbosity_level >= 20) SERIAL_ECHOLNPGM("Y searching radius lower than Y_MIN. Clamping was done."); + } + if (y1 > Y_MAX_POS) { + y1 = Y_MAX_POS; + if (verbosity_level >= 20) SERIAL_ECHOLNPGM("Y searching radius higher than X_MAX. Clamping was done."); + } + nsteps_y = int(ceil((y1 - y0) / FIND_BED_INDUCTION_SENSOR_POINT_XY_STEP)); + + enable_endstops(false); + bool dir_positive = true; + +// go_xyz(current_position[X_AXIS], current_position[Y_AXIS], MESH_HOME_Z_SEARCH, homing_feedrate[Z_AXIS]/60); + go_xyz(x0, y0, current_position[Z_AXIS], feedrate); + // Continously lower the Z axis. + endstops_hit_on_purpose(); + enable_z_endstop(true); + while (current_position[Z_AXIS] > -10.f) { + // Do nsteps_y zig-zag movements. + current_position[Y_AXIS] = y0; + for (i = 0; i < nsteps_y; current_position[Y_AXIS] += (y1 - y0) / float(nsteps_y - 1), ++ i) { + // Run with a slightly decreasing Z axis, zig-zag movement. Stop at the Z end-stop. + current_position[Z_AXIS] -= FIND_BED_INDUCTION_SENSOR_POINT_Z_STEP / float(nsteps_y); + go_xyz(dir_positive ? x1 : x0, current_position[Y_AXIS], current_position[Z_AXIS], feedrate); + dir_positive = ! dir_positive; + if (endstop_z_hit_on_purpose()) + goto endloop; + } + for (i = 0; i < nsteps_y; current_position[Y_AXIS] -= (y1 - y0) / float(nsteps_y - 1), ++ i) { + // Run with a slightly decreasing Z axis, zig-zag movement. Stop at the Z end-stop. + current_position[Z_AXIS] -= FIND_BED_INDUCTION_SENSOR_POINT_Z_STEP / float(nsteps_y); + go_xyz(dir_positive ? x1 : x0, current_position[Y_AXIS], current_position[Z_AXIS], feedrate); + dir_positive = ! dir_positive; + if (endstop_z_hit_on_purpose()) + goto endloop; + } + } + endloop: +// SERIAL_ECHOLN("First hit"); + + // we have to let the planner know where we are right now as it is not where we said to go. + update_current_position_xyz(); + + // Search in this plane for the first hit. Zig-zag first in X, then in Y axis. + for (int8_t iter = 0; iter < 3; ++ iter) { + if (iter > 0) { + // Slightly lower the Z axis to get a reliable trigger. + current_position[Z_AXIS] -= 0.02f; + go_xyz(current_position[X_AXIS], current_position[Y_AXIS], MESH_HOME_Z_SEARCH, homing_feedrate[Z_AXIS]/60); + } + + // Do nsteps_y zig-zag movements. + float a, b; + enable_endstops(false); + enable_z_endstop(false); + current_position[Y_AXIS] = y0; + go_xy(x0, current_position[Y_AXIS], feedrate); + enable_z_endstop(true); + found = false; + for (i = 0, dir_positive = true; i < nsteps_y; current_position[Y_AXIS] += (y1 - y0) / float(nsteps_y - 1), ++ i, dir_positive = ! dir_positive) { + go_xy(dir_positive ? x1 : x0, current_position[Y_AXIS], feedrate); + if (endstop_z_hit_on_purpose()) { + found = true; + break; + } + } + update_current_position_xyz(); + if (! found) { +// SERIAL_ECHOLN("Search in Y - not found"); + continue; + } +// SERIAL_ECHOLN("Search in Y - found"); + a = current_position[Y_AXIS]; + + enable_z_endstop(false); + current_position[Y_AXIS] = y1; + go_xy(x0, current_position[Y_AXIS], feedrate); + enable_z_endstop(true); + found = false; + for (i = 0, dir_positive = true; i < nsteps_y; current_position[Y_AXIS] -= (y1 - y0) / float(nsteps_y - 1), ++ i, dir_positive = ! dir_positive) { + go_xy(dir_positive ? x1 : x0, current_position[Y_AXIS], feedrate); + if (endstop_z_hit_on_purpose()) { + found = true; + break; + } + } + update_current_position_xyz(); + if (! found) { +// SERIAL_ECHOLN("Search in Y2 - not found"); + continue; + } +// SERIAL_ECHOLN("Search in Y2 - found"); + b = current_position[Y_AXIS]; + current_position[Y_AXIS] = 0.5f * (a + b); + + // Search in the X direction along a cross. + found = false; + enable_z_endstop(false); + go_xy(x0, current_position[Y_AXIS], feedrate); + enable_z_endstop(true); + go_xy(x1, current_position[Y_AXIS], feedrate); + update_current_position_xyz(); + if (! endstop_z_hit_on_purpose()) { +// SERIAL_ECHOLN("Search X span 0 - not found"); + continue; + } +// SERIAL_ECHOLN("Search X span 0 - found"); + a = current_position[X_AXIS]; + enable_z_endstop(false); + go_xy(x1, current_position[Y_AXIS], feedrate); + enable_z_endstop(true); + go_xy(x0, current_position[Y_AXIS], feedrate); + update_current_position_xyz(); + if (! endstop_z_hit_on_purpose()) { +// SERIAL_ECHOLN("Search X span 1 - not found"); + continue; + } +// SERIAL_ECHOLN("Search X span 1 - found"); + b = current_position[X_AXIS]; + // Go to the center. + enable_z_endstop(false); + current_position[X_AXIS] = 0.5f * (a + b); + go_xy(current_position[X_AXIS], current_position[Y_AXIS], feedrate); + found = true; + +#if 1 + // Search in the Y direction along a cross. + found = false; + enable_z_endstop(false); + go_xy(current_position[X_AXIS], y0, feedrate); + enable_z_endstop(true); + go_xy(current_position[X_AXIS], y1, feedrate); + update_current_position_xyz(); + if (! endstop_z_hit_on_purpose()) { +// SERIAL_ECHOLN("Search Y2 span 0 - not found"); + continue; + } +// SERIAL_ECHOLN("Search Y2 span 0 - found"); + a = current_position[Y_AXIS]; + enable_z_endstop(false); + go_xy(current_position[X_AXIS], y1, feedrate); + enable_z_endstop(true); + go_xy(current_position[X_AXIS], y0, feedrate); + update_current_position_xyz(); + if (! endstop_z_hit_on_purpose()) { +// SERIAL_ECHOLN("Search Y2 span 1 - not found"); + continue; + } +// SERIAL_ECHOLN("Search Y2 span 1 - found"); + b = current_position[Y_AXIS]; + // Go to the center. + enable_z_endstop(false); + current_position[Y_AXIS] = 0.5f * (a + b); + go_xy(current_position[X_AXIS], current_position[Y_AXIS], feedrate); + found = true; +#endif + break; + } + } + + enable_z_endstop(false); + return found; +} + +// Search around the current_position[X,Y,Z]. +// It is expected, that the induction sensor is switched on at the current position. +// Look around this center point by painting a star around the point. +inline bool improve_bed_induction_sensor_point() +{ + static const float search_radius = 8.f; + + bool endstops_enabled = enable_endstops(false); + bool endstop_z_enabled = enable_z_endstop(false); + bool found = false; + float feedrate = homing_feedrate[X_AXIS] / 60.f; + float center_old_x = current_position[X_AXIS]; + float center_old_y = current_position[Y_AXIS]; + float center_x = 0.f; + float center_y = 0.f; + + for (uint8_t iter = 0; iter < 4; ++ iter) { + switch (iter) { + case 0: + destination[X_AXIS] = center_old_x - search_radius * 0.707; + destination[Y_AXIS] = center_old_y - search_radius * 0.707; + break; + case 1: + destination[X_AXIS] = center_old_x + search_radius * 0.707; + destination[Y_AXIS] = center_old_y + search_radius * 0.707; + break; + case 2: + destination[X_AXIS] = center_old_x + search_radius * 0.707; + destination[Y_AXIS] = center_old_y - search_radius * 0.707; + break; + case 3: + default: + destination[X_AXIS] = center_old_x - search_radius * 0.707; + destination[Y_AXIS] = center_old_y + search_radius * 0.707; + break; + } + + // Trim the vector from center_old_[x,y] to destination[x,y] by the bed dimensions. + float vx = destination[X_AXIS] - center_old_x; + float vy = destination[Y_AXIS] - center_old_y; + float l = sqrt(vx*vx+vy*vy); + float t; + if (destination[X_AXIS] < X_MIN_POS) { + // Exiting the bed at xmin. + t = (center_x - X_MIN_POS) / l; + destination[X_AXIS] = X_MIN_POS; + destination[Y_AXIS] = center_old_y + t * vy; + } else if (destination[X_AXIS] > X_MAX_POS) { + // Exiting the bed at xmax. + t = (X_MAX_POS - center_x) / l; + destination[X_AXIS] = X_MAX_POS; + destination[Y_AXIS] = center_old_y + t * vy; + } + if (destination[Y_AXIS] < Y_MIN_POS_FOR_BED_CALIBRATION) { + // Exiting the bed at ymin. + t = (center_y - Y_MIN_POS_FOR_BED_CALIBRATION) / l; + destination[X_AXIS] = center_old_x + t * vx; + destination[Y_AXIS] = Y_MIN_POS_FOR_BED_CALIBRATION; + } else if (destination[Y_AXIS] > Y_MAX_POS) { + // Exiting the bed at xmax. + t = (Y_MAX_POS - center_y) / l; + destination[X_AXIS] = center_old_x + t * vx; + destination[Y_AXIS] = Y_MAX_POS; + } + + // Move away from the measurement point. + enable_endstops(false); + go_xy(destination[X_AXIS], destination[Y_AXIS], feedrate); + // Move towards the measurement point, until the induction sensor triggers. + enable_endstops(true); + go_xy(center_old_x, center_old_y, feedrate); + update_current_position_xyz(); +// if (! endstop_z_hit_on_purpose()) return false; + center_x += current_position[X_AXIS]; + center_y += current_position[Y_AXIS]; + } + + // Calculate the new center, move to the new center. + center_x /= 4.f; + center_y /= 4.f; + current_position[X_AXIS] = center_x; + current_position[Y_AXIS] = center_y; + enable_endstops(false); + go_xy(current_position[X_AXIS], current_position[Y_AXIS], feedrate); + + enable_endstops(endstops_enabled); + enable_z_endstop(endstop_z_enabled); + return found; +} + +static inline void debug_output_point(const char *type, const float &x, const float &y, const float &z) +{ + SERIAL_ECHOPGM("Measured "); + SERIAL_ECHORPGM(type); + SERIAL_ECHOPGM(" "); + MYSERIAL.print(x, 5); + SERIAL_ECHOPGM(", "); + MYSERIAL.print(y, 5); + SERIAL_ECHOPGM(", "); + MYSERIAL.print(z, 5); + SERIAL_ECHOLNPGM(""); +} + +// Search around the current_position[X,Y,Z]. +// It is expected, that the induction sensor is switched on at the current position. +// Look around this center point by painting a star around the point. +#define IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS (8.f) +inline bool improve_bed_induction_sensor_point2(bool lift_z_on_min_y, int8_t verbosity_level) +{ + float center_old_x = current_position[X_AXIS]; + float center_old_y = current_position[Y_AXIS]; + float a, b; + bool point_small = false; + + enable_endstops(false); + + { + float x0 = center_old_x - IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS; + float x1 = center_old_x + IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS; + if (x0 < X_MIN_POS) + x0 = X_MIN_POS; + if (x1 > X_MAX_POS) + x1 = X_MAX_POS; + + // Search in the X direction along a cross. + enable_z_endstop(false); + go_xy(x0, current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f); + enable_z_endstop(true); + go_xy(x1, current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f); + update_current_position_xyz(); + if (! endstop_z_hit_on_purpose()) { + current_position[X_AXIS] = center_old_x; + goto canceled; + } + a = current_position[X_AXIS]; + enable_z_endstop(false); + go_xy(x1, current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f); + enable_z_endstop(true); + go_xy(x0, current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f); + update_current_position_xyz(); + if (! endstop_z_hit_on_purpose()) { + current_position[X_AXIS] = center_old_x; + goto canceled; + } + b = current_position[X_AXIS]; + if (b - a < MIN_BED_SENSOR_POINT_RESPONSE_DMR) { + if (verbosity_level >= 5) { + SERIAL_ECHOPGM("Point width too small: "); + SERIAL_ECHO(b - a); + SERIAL_ECHOLNPGM(""); + } + // We force the calibration routine to move the Z axis slightly down to make the response more pronounced. + if (b - a < 0.5f * MIN_BED_SENSOR_POINT_RESPONSE_DMR) { + // Don't use the new X value. + current_position[X_AXIS] = center_old_x; + goto canceled; + } else { + // Use the new value, but force the Z axis to go a bit lower. + point_small = true; + } + } + if (verbosity_level >= 5) { + debug_output_point(PSTR("left" ), a, current_position[Y_AXIS], current_position[Z_AXIS]); + debug_output_point(PSTR("right"), b, current_position[Y_AXIS], current_position[Z_AXIS]); + } + + // Go to the center. + enable_z_endstop(false); + current_position[X_AXIS] = 0.5f * (a + b); + go_xy(current_position[X_AXIS], current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f); + } + + { + float y0 = center_old_y - IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS; + float y1 = center_old_y + IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS; + if (y0 < Y_MIN_POS_FOR_BED_CALIBRATION) + y0 = Y_MIN_POS_FOR_BED_CALIBRATION; + if (y1 > Y_MAX_POS) + y1 = Y_MAX_POS; + + // Search in the Y direction along a cross. + enable_z_endstop(false); + go_xy(current_position[X_AXIS], y0, homing_feedrate[X_AXIS] / 60.f); + if (lift_z_on_min_y) { + // The first row of points are very close to the end stop. + // Lift the sensor to disengage the trigger. This is necessary because of the sensor hysteresis. + go_xyz(current_position[X_AXIS], y0, current_position[Z_AXIS]+1.5f, homing_feedrate[Z_AXIS] / 60.f); + // and go back. + go_xyz(current_position[X_AXIS], y0, current_position[Z_AXIS], homing_feedrate[Z_AXIS] / 60.f); + } + if (lift_z_on_min_y && (READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING) == 1) { + // Already triggering before we started the move. + // Shift the trigger point slightly outwards. + // a = current_position[Y_AXIS] - 1.5f; + a = current_position[Y_AXIS]; + } else { + enable_z_endstop(true); + go_xy(current_position[X_AXIS], y1, homing_feedrate[X_AXIS] / 60.f); + update_current_position_xyz(); + if (! endstop_z_hit_on_purpose()) { + current_position[Y_AXIS] = center_old_y; + goto canceled; + } + a = current_position[Y_AXIS]; + } + enable_z_endstop(false); + go_xy(current_position[X_AXIS], y1, homing_feedrate[X_AXIS] / 60.f); + enable_z_endstop(true); + go_xy(current_position[X_AXIS], y0, homing_feedrate[X_AXIS] / 60.f); + update_current_position_xyz(); + if (! endstop_z_hit_on_purpose()) { + current_position[Y_AXIS] = center_old_y; + goto canceled; + } + b = current_position[Y_AXIS]; + if (b - a < MIN_BED_SENSOR_POINT_RESPONSE_DMR) { + // We force the calibration routine to move the Z axis slightly down to make the response more pronounced. + if (verbosity_level >= 5) { + SERIAL_ECHOPGM("Point height too small: "); + SERIAL_ECHO(b - a); + SERIAL_ECHOLNPGM(""); + } + if (b - a < 0.5f * MIN_BED_SENSOR_POINT_RESPONSE_DMR) { + // Don't use the new Y value. + current_position[Y_AXIS] = center_old_y; + goto canceled; + } else { + // Use the new value, but force the Z axis to go a bit lower. + point_small = true; + } + } + if (verbosity_level >= 5) { + debug_output_point(PSTR("top" ), current_position[X_AXIS], a, current_position[Z_AXIS]); + debug_output_point(PSTR("bottom"), current_position[X_AXIS], b, current_position[Z_AXIS]); + } + + // Go to the center. + enable_z_endstop(false); + current_position[Y_AXIS] = 0.5f * (a + b); + go_xy(current_position[X_AXIS], current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f); + } + + // If point is small but not too small, then force the Z axis to be lowered a bit, + // but use the new value. This is important when the initial position was off in one axis, + // for example if the initial calibration was shifted in the Y axis systematically. + // Then this first step will center. + return ! point_small; + +canceled: + // Go back to the center. + enable_z_endstop(false); + go_xy(current_position[X_AXIS], current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f); + return false; +} + +// Searching the front points, where one cannot move the sensor head in front of the sensor point. +// Searching in a zig-zag movement in a plane for the maximum width of the response. +// This function may set the current_position[Y_AXIS] below Y_MIN_POS, if the function succeeded. +// If this function failed, the Y coordinate will never be outside the working space. +#define IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS (4.f) +#define IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y (0.1f) +inline bool improve_bed_induction_sensor_point3(int verbosity_level) +{ + float center_old_x = current_position[X_AXIS]; + float center_old_y = current_position[Y_AXIS]; + float a, b; + bool result = true; + + if (verbosity_level >= 20) MYSERIAL.println("Improve bed induction sensor point3"); + // Was the sensor point detected too far in the minus Y axis? + // If yes, the center of the induction point cannot be reached by the machine. + { + float x0 = center_old_x - IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS; + float x1 = center_old_x + IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS; + float y0 = center_old_y - IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS; + float y1 = center_old_y + IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS; + float y = y0; + + if (x0 < X_MIN_POS) + x0 = X_MIN_POS; + if (x1 > X_MAX_POS) + x1 = X_MAX_POS; + if (y0 < Y_MIN_POS_FOR_BED_CALIBRATION) + y0 = Y_MIN_POS_FOR_BED_CALIBRATION; + if (y1 > Y_MAX_POS) + y1 = Y_MAX_POS; + + if (verbosity_level >= 20) { + SERIAL_ECHOPGM("Initial position: "); + SERIAL_ECHO(center_old_x); + SERIAL_ECHOPGM(", "); + SERIAL_ECHO(center_old_y); + SERIAL_ECHOLNPGM(""); + } + + // Search in the positive Y direction, until a maximum diameter is found. + // (the next diameter is smaller than the current one.) + float dmax = 0.f; + float xmax1 = 0.f; + float xmax2 = 0.f; + for (y = y0; y < y1; y += IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y) { + enable_z_endstop(false); + go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f); + enable_z_endstop(true); + go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f); + update_current_position_xyz(); + if (! endstop_z_hit_on_purpose()) { + continue; + // SERIAL_PROTOCOLPGM("Failed 1\n"); + // current_position[X_AXIS] = center_old_x; + // goto canceled; + } + a = current_position[X_AXIS]; + enable_z_endstop(false); + go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f); + enable_z_endstop(true); + go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f); + update_current_position_xyz(); + if (! endstop_z_hit_on_purpose()) { + continue; + // SERIAL_PROTOCOLPGM("Failed 2\n"); + // current_position[X_AXIS] = center_old_x; + // goto canceled; + } + b = current_position[X_AXIS]; + if (verbosity_level >= 5) { + debug_output_point(PSTR("left" ), a, current_position[Y_AXIS], current_position[Z_AXIS]); + debug_output_point(PSTR("right"), b, current_position[Y_AXIS], current_position[Z_AXIS]); + } + float d = b - a; + if (d > dmax) { + xmax1 = 0.5f * (a + b); + dmax = d; + } else if (dmax > 0.) { + y0 = y - IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y; + break; + } + } + if (dmax == 0.) { + if (verbosity_level > 0) + SERIAL_PROTOCOLPGM("failed - not found\n"); + current_position[X_AXIS] = center_old_x; + current_position[Y_AXIS] = center_old_y; + goto canceled; + } + + { + // Find the positive Y hit. This gives the extreme Y value for the search of the maximum diameter in the -Y direction. + enable_z_endstop(false); + go_xy(xmax1, y0 + IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS, homing_feedrate[X_AXIS] / 60.f); + enable_z_endstop(true); + go_xy(xmax1, max(y0 - IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS, Y_MIN_POS_FOR_BED_CALIBRATION), homing_feedrate[X_AXIS] / 60.f); + update_current_position_xyz(); + if (! endstop_z_hit_on_purpose()) { + current_position[Y_AXIS] = center_old_y; + goto canceled; + } + if (verbosity_level >= 5) + debug_output_point(PSTR("top" ), current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]); + y1 = current_position[Y_AXIS]; + } + + if (y1 <= y0) { + // Either the induction sensor is too high, or the induction sensor target is out of reach. + current_position[Y_AXIS] = center_old_y; + goto canceled; + } + + // Search in the negative Y direction, until a maximum diameter is found. + dmax = 0.f; + // if (y0 + 1.f < y1) + // y1 = y0 + 1.f; + for (y = y1; y >= y0; y -= IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y) { + enable_z_endstop(false); + go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f); + enable_z_endstop(true); + go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f); + update_current_position_xyz(); + if (! endstop_z_hit_on_purpose()) { + continue; + /* + current_position[X_AXIS] = center_old_x; + SERIAL_PROTOCOLPGM("Failed 3\n"); + goto canceled; + */ + } + a = current_position[X_AXIS]; + enable_z_endstop(false); + go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f); + enable_z_endstop(true); + go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f); + update_current_position_xyz(); + if (! endstop_z_hit_on_purpose()) { + continue; + /* + current_position[X_AXIS] = center_old_x; + SERIAL_PROTOCOLPGM("Failed 4\n"); + goto canceled; + */ + } + b = current_position[X_AXIS]; + if (verbosity_level >= 5) { + debug_output_point(PSTR("left" ), a, current_position[Y_AXIS], current_position[Z_AXIS]); + debug_output_point(PSTR("right"), b, current_position[Y_AXIS], current_position[Z_AXIS]); + } + float d = b - a; + if (d > dmax) { + xmax2 = 0.5f * (a + b); + dmax = d; + } else if (dmax > 0.) { + y1 = y + IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y; + break; + } + } + float xmax, ymax; + if (dmax == 0.f) { + // Only the hit in the positive direction found. + xmax = xmax1; + ymax = y0; + } else { + // Both positive and negative directions found. + xmax = xmax2; + ymax = 0.5f * (y0 + y1); + for (; y >= y0; y -= IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y) { + enable_z_endstop(false); + go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f); + enable_z_endstop(true); + go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f); + update_current_position_xyz(); + if (! endstop_z_hit_on_purpose()) { + continue; + /* + current_position[X_AXIS] = center_old_x; + SERIAL_PROTOCOLPGM("Failed 3\n"); + goto canceled; + */ + } + a = current_position[X_AXIS]; + enable_z_endstop(false); + go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f); + enable_z_endstop(true); + go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f); + update_current_position_xyz(); + if (! endstop_z_hit_on_purpose()) { + continue; + /* + current_position[X_AXIS] = center_old_x; + SERIAL_PROTOCOLPGM("Failed 4\n"); + goto canceled; + */ + } + b = current_position[X_AXIS]; + if (verbosity_level >= 5) { + debug_output_point(PSTR("left" ), a, current_position[Y_AXIS], current_position[Z_AXIS]); + debug_output_point(PSTR("right"), b, current_position[Y_AXIS], current_position[Z_AXIS]); + } + float d = b - a; + if (d > dmax) { + xmax = 0.5f * (a + b); + ymax = y; + dmax = d; + } + } + } + + { + // Compare the distance in the Y+ direction with the diameter in the X direction. + // Find the positive Y hit once again, this time along the Y axis going through the X point with the highest diameter. + enable_z_endstop(false); + go_xy(xmax, ymax + IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS, homing_feedrate[X_AXIS] / 60.f); + enable_z_endstop(true); + go_xy(xmax, max(ymax - IMPROVE_BED_INDUCTION_SENSOR_SEARCH_RADIUS, Y_MIN_POS_FOR_BED_CALIBRATION), homing_feedrate[X_AXIS] / 60.f); + update_current_position_xyz(); + if (! endstop_z_hit_on_purpose()) { + current_position[Y_AXIS] = center_old_y; + goto canceled; + } + if (verbosity_level >= 5) + debug_output_point(PSTR("top" ), current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]); + if (current_position[Y_AXIS] - Y_MIN_POS_FOR_BED_CALIBRATION < 0.5f * dmax) { + // Probably not even a half circle was detected. The induction point is likely too far in the minus Y direction. + // First verify, if the measurement has been done at a sufficient height. If no, lower the Z axis a bit. + if (current_position[Y_AXIS] < ymax || dmax < 0.5f * MIN_BED_SENSOR_POINT_RESPONSE_DMR) { + if (verbosity_level >= 5) { + SERIAL_ECHOPGM("Partial point diameter too small: "); + SERIAL_ECHO(dmax); + SERIAL_ECHOLNPGM(""); + } + result = false; + } else { + // Estimate the circle radius from the maximum diameter and height: + float h = current_position[Y_AXIS] - ymax; + float r = dmax * dmax / (8.f * h) + 0.5f * h; + if (r < 0.8f * MIN_BED_SENSOR_POINT_RESPONSE_DMR) { + if (verbosity_level >= 5) { + SERIAL_ECHOPGM("Partial point estimated radius too small: "); + SERIAL_ECHO(r); + SERIAL_ECHOPGM(", dmax:"); + SERIAL_ECHO(dmax); + SERIAL_ECHOPGM(", h:"); + SERIAL_ECHO(h); + SERIAL_ECHOLNPGM(""); + } + result = false; + } else { + // The point may end up outside of the machine working space. + // That is all right as it helps to improve the accuracy of the measurement point + // due to averaging. + // For the y correction, use an average of dmax/2 and the estimated radius. + r = 0.5f * (0.5f * dmax + r); + ymax = current_position[Y_AXIS] - r; + } + } + } else { + // If the diameter of the detected spot was smaller than a minimum allowed, + // the induction sensor is probably too high. Returning false will force + // the sensor to be lowered a tiny bit. + result = xmax >= MIN_BED_SENSOR_POINT_RESPONSE_DMR; + if (y0 > Y_MIN_POS_FOR_BED_CALIBRATION + 0.2f) + // Only in case both left and right y tangents are known, use them. + // If y0 is close to the bed edge, it may not be symmetric to the right tangent. + ymax = 0.5f * ymax + 0.25f * (y0 + y1); + } + } + + // Go to the center. + enable_z_endstop(false); + current_position[X_AXIS] = xmax; + current_position[Y_AXIS] = ymax; + if (verbosity_level >= 20) { + SERIAL_ECHOPGM("Adjusted position: "); + SERIAL_ECHO(current_position[X_AXIS]); + SERIAL_ECHOPGM(", "); + SERIAL_ECHO(current_position[Y_AXIS]); + SERIAL_ECHOLNPGM(""); + } + + // Don't clamp current_position[Y_AXIS], because the out-of-reach Y coordinate may actually be true. + // Only clamp the coordinate to go. + go_xy(current_position[X_AXIS], max(Y_MIN_POS, current_position[Y_AXIS]), homing_feedrate[X_AXIS] / 60.f); + // delay_keep_alive(3000); + } + + if (result) + return true; + // otherwise clamp the Y coordinate + +canceled: + // Go back to the center. + enable_z_endstop(false); + if (current_position[Y_AXIS] < Y_MIN_POS) + current_position[Y_AXIS] = Y_MIN_POS; + go_xy(current_position[X_AXIS], current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f); + return false; +} + +// Scan the mesh bed induction points one by one by a left-right zig-zag movement, +// write the trigger coordinates to the serial line. +// Useful for visualizing the behavior of the bed induction detector. +inline void scan_bed_induction_sensor_point() +{ + float center_old_x = current_position[X_AXIS]; + float center_old_y = current_position[Y_AXIS]; + float x0 = center_old_x - IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS; + float x1 = center_old_x + IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS; + float y0 = center_old_y - IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS; + float y1 = center_old_y + IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS; + float y = y0; + + if (x0 < X_MIN_POS) + x0 = X_MIN_POS; + if (x1 > X_MAX_POS) + x1 = X_MAX_POS; + if (y0 < Y_MIN_POS_FOR_BED_CALIBRATION) + y0 = Y_MIN_POS_FOR_BED_CALIBRATION; + if (y1 > Y_MAX_POS) + y1 = Y_MAX_POS; + + for (float y = y0; y < y1; y += IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y) { + enable_z_endstop(false); + go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f); + enable_z_endstop(true); + go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f); + update_current_position_xyz(); + if (endstop_z_hit_on_purpose()) + debug_output_point(PSTR("left" ), current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]); + enable_z_endstop(false); + go_xy(x1, y, homing_feedrate[X_AXIS] / 60.f); + enable_z_endstop(true); + go_xy(x0, y, homing_feedrate[X_AXIS] / 60.f); + update_current_position_xyz(); + if (endstop_z_hit_on_purpose()) + debug_output_point(PSTR("right"), current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]); + } + + enable_z_endstop(false); + current_position[X_AXIS] = center_old_x; + current_position[Y_AXIS] = center_old_y; + go_xy(current_position[X_AXIS], current_position[Y_AXIS], homing_feedrate[X_AXIS] / 60.f); +} + +#define MESH_BED_CALIBRATION_SHOW_LCD + +BedSkewOffsetDetectionResultType find_bed_offset_and_skew(int8_t verbosity_level, uint8_t &too_far_mask) +{ + // Don't let the manage_inactivity() function remove power from the motors. + refresh_cmd_timeout(); + + // Reusing the z_values memory for the measurement cache. + // 7x7=49 floats, good for 16 (x,y,z) vectors. + float *pts = &mbl.z_values[0][0]; + float *vec_x = pts + 2 * 4; + float *vec_y = vec_x + 2; + float *cntr = vec_y + 2; + memset(pts, 0, sizeof(float) * 7 * 7); + uint8_t iteration = 0; + BedSkewOffsetDetectionResultType result; + +// SERIAL_ECHOLNPGM("find_bed_offset_and_skew verbosity level: "); +// SERIAL_ECHO(int(verbosity_level)); +// SERIAL_ECHOPGM(""); + + while (iteration < 3) { + + SERIAL_ECHOPGM("Iteration: "); + MYSERIAL.println(int(iteration + 1)); + if (verbosity_level >= 20) { + SERIAL_ECHOLNPGM("Vectors: "); + + SERIAL_ECHOPGM("vec_x[0]:"); + MYSERIAL.print(vec_x[0], 5); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("vec_x[1]:"); + MYSERIAL.print(vec_x[1], 5); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("vec_y[0]:"); + MYSERIAL.print(vec_y[0], 5); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("vec_y[1]:"); + MYSERIAL.print(vec_y[1], 5); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("cntr[0]:"); + MYSERIAL.print(cntr[0], 5); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("cntr[1]:"); + MYSERIAL.print(cntr[1], 5); + SERIAL_ECHOLNPGM(""); + } +#ifdef MESH_BED_CALIBRATION_SHOW_LCD + uint8_t next_line; + lcd_display_message_fullscreen_P(MSG_FIND_BED_OFFSET_AND_SKEW_LINE1, next_line); + if (next_line > 3) + next_line = 3; +#endif /* MESH_BED_CALIBRATION_SHOW_LCD */ + + // Collect the rear 2x3 points. + current_position[Z_AXIS] = MESH_HOME_Z_SEARCH + FIND_BED_INDUCTION_SENSOR_POINT_Z_STEP * iteration * 0.3; + for (int k = 0; k < 4; ++k) { + // Don't let the manage_inactivity() function remove power from the motors. + refresh_cmd_timeout(); +#ifdef MESH_BED_CALIBRATION_SHOW_LCD + lcd_implementation_print_at(0, next_line, k + 1); + lcd_printPGM(MSG_FIND_BED_OFFSET_AND_SKEW_LINE2); + + if (iteration > 0) { + lcd_print_at_PGM(0, next_line + 1, MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION); + lcd_implementation_print(int(iteration + 1)); + } +#endif /* MESH_BED_CALIBRATION_SHOW_LCD */ + float *pt = pts + k * 2; + // Go up to z_initial. + + go_to_current(homing_feedrate[Z_AXIS] / 60.f); + if (verbosity_level >= 20) { + // Go to Y0, wait, then go to Y-4. + current_position[Y_AXIS] = 0.f; + go_to_current(homing_feedrate[X_AXIS] / 60.f); + SERIAL_ECHOLNPGM("At Y0"); + delay_keep_alive(5000); + current_position[Y_AXIS] = Y_MIN_POS; + go_to_current(homing_feedrate[X_AXIS] / 60.f); + SERIAL_ECHOLNPGM("At Y-4"); + delay_keep_alive(5000); + } + // Go to the measurement point position. + //if (iteration == 0) { + current_position[X_AXIS] = pgm_read_float(bed_ref_points_4 + k * 2); + current_position[Y_AXIS] = pgm_read_float(bed_ref_points_4 + k * 2 + 1); + /*} + else { + // if first iteration failed, count corrected point coordinates as initial + // Use the coorrected coordinate, which is a result of find_bed_offset_and_skew(). + + current_position[X_AXIS] = vec_x[0] * pgm_read_float(bed_ref_points_4 + k * 2) + vec_y[0] * pgm_read_float(bed_ref_points_4 + k * 2 + 1) + cntr[0]; + current_position[Y_AXIS] = vec_x[1] * pgm_read_float(bed_ref_points_4 + k * 2) + vec_y[1] * pgm_read_float(bed_ref_points_4 + k * 2 + 1) + cntr[1]; + + // The calibration points are very close to the min Y. + if (current_position[Y_AXIS] < Y_MIN_POS_FOR_BED_CALIBRATION) + current_position[Y_AXIS] = Y_MIN_POS_FOR_BED_CALIBRATION; + + }*/ + if (verbosity_level >= 20) { + SERIAL_ECHOPGM("current_position[X_AXIS]:"); + MYSERIAL.print(current_position[X_AXIS], 5); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("current_position[Y_AXIS]:"); + MYSERIAL.print(current_position[Y_AXIS], 5); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("current_position[Z_AXIS]:"); + MYSERIAL.print(current_position[Z_AXIS], 5); + SERIAL_ECHOLNPGM(""); + } + + + go_to_current(homing_feedrate[X_AXIS] / 60.f); + if (verbosity_level >= 10) + delay_keep_alive(3000); + if (!find_bed_induction_sensor_point_xy(verbosity_level)) + return BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND; +#if 1 + + if (k == 0) { + // Improve the position of the 1st row sensor points by a zig-zag movement. + find_bed_induction_sensor_point_z(); + int8_t i = 4; + for (;;) { + if (improve_bed_induction_sensor_point3(verbosity_level)) + break; + if (--i == 0) + return BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND; + // Try to move the Z axis down a bit to increase a chance of the sensor to trigger. + current_position[Z_AXIS] -= 0.025f; + enable_endstops(false); + enable_z_endstop(false); + go_to_current(homing_feedrate[Z_AXIS]); + } + if (i == 0) + // not found + return BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND; + } +#endif + if (verbosity_level >= 10) + delay_keep_alive(3000); + // Save the detected point position and then clamp the Y coordinate, which may have been estimated + // to lie outside the machine working space. + if (verbosity_level >= 20) { + SERIAL_ECHOLNPGM("Measured:"); + MYSERIAL.println(current_position[X_AXIS]); + MYSERIAL.println(current_position[Y_AXIS]); + } + pt[0] = (pt[0] * iteration) / (iteration + 1); + pt[0] += (current_position[X_AXIS]/(iteration + 1)); //count average + pt[1] = (pt[1] * iteration) / (iteration + 1); + pt[1] += (current_position[Y_AXIS] / (iteration + 1)); + + + //pt[0] += current_position[X_AXIS]; + //if(iteration > 0) pt[0] = pt[0] / 2; + + //pt[1] += current_position[Y_AXIS]; + //if (iteration > 0) pt[1] = pt[1] / 2; + + if (verbosity_level >= 20) { + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("pt[0]:"); + MYSERIAL.println(pt[0]); + SERIAL_ECHOPGM("pt[1]:"); + MYSERIAL.println(pt[1]); + } + + if (current_position[Y_AXIS] < Y_MIN_POS) + current_position[Y_AXIS] = Y_MIN_POS; + // Start searching for the other points at 3mm above the last point. + current_position[Z_AXIS] += 3.f + FIND_BED_INDUCTION_SENSOR_POINT_Z_STEP * iteration * 0.3; + //cntr[0] += pt[0]; + //cntr[1] += pt[1]; + if (verbosity_level >= 10 && k == 0) { + // Show the zero. Test, whether the Y motor skipped steps. + current_position[Y_AXIS] = MANUAL_Y_HOME_POS; + go_to_current(homing_feedrate[X_AXIS] / 60.f); + delay_keep_alive(3000); + } + } + + if (verbosity_level >= 20) { + // Test the positions. Are the positions reproducible? Now the calibration is active in the planner. + delay_keep_alive(3000); + for (int8_t mesh_point = 0; mesh_point < 4; ++mesh_point) { + // Don't let the manage_inactivity() function remove power from the motors. + refresh_cmd_timeout(); + // Go to the measurement point. + // Use the coorrected coordinate, which is a result of find_bed_offset_and_skew(). + current_position[X_AXIS] = pts[mesh_point * 2]; + current_position[Y_AXIS] = pts[mesh_point * 2 + 1]; + go_to_current(homing_feedrate[X_AXIS] / 60); + delay_keep_alive(3000); + } + } + + if (pts[1] < Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH) { + too_far_mask |= 1 << 1; //front center point is out of reach + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("WARNING: Front point not reachable. Y coordinate:"); + MYSERIAL.print(pts[1]); + SERIAL_ECHOPGM(" < "); + MYSERIAL.println(Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH); + } + + result = calculate_machine_skew_and_offset_LS(pts, 4, bed_ref_points_4, vec_x, vec_y, cntr, verbosity_level); + if (result >= 0) { + world2machine_update(vec_x, vec_y, cntr); +#if 1 + // Fearlessly store the calibration values into the eeprom. + eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_CENTER + 0), cntr[0]); + eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_CENTER + 4), cntr[1]); + eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_X + 0), vec_x[0]); + eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_X + 4), vec_x[1]); + eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y + 0), vec_y[0]); + eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y + 4), vec_y[1]); +#endif + if (verbosity_level >= 10) { + // Length of the vec_x + float l = sqrt(vec_x[0] * vec_x[0] + vec_x[1] * vec_x[1]); + SERIAL_ECHOLNPGM("X vector length:"); + MYSERIAL.println(l); + + // Length of the vec_y + l = sqrt(vec_y[0] * vec_y[0] + vec_y[1] * vec_y[1]); + SERIAL_ECHOLNPGM("Y vector length:"); + MYSERIAL.println(l); + // Zero point correction + l = sqrt(cntr[0] * cntr[0] + cntr[1] * cntr[1]); + SERIAL_ECHOLNPGM("Zero point correction:"); + MYSERIAL.println(l); + + // vec_x and vec_y shall be nearly perpendicular. + l = vec_x[0] * vec_y[0] + vec_x[1] * vec_y[1]; + SERIAL_ECHOLNPGM("Perpendicularity"); + MYSERIAL.println(fabs(l)); + SERIAL_ECHOLNPGM("Saving bed calibration vectors to EEPROM"); + } + // Correct the current_position to match the transformed coordinate system after world2machine_rotation_and_skew and world2machine_shift were set. + world2machine_update_current(); + + + if (verbosity_level >= 20) { + // Test the positions. Are the positions reproducible? Now the calibration is active in the planner. + delay_keep_alive(3000); + for (int8_t mesh_point = 0; mesh_point < 9; ++mesh_point) { + // Don't let the manage_inactivity() function remove power from the motors. + refresh_cmd_timeout(); + // Go to the measurement point. + // Use the coorrected coordinate, which is a result of find_bed_offset_and_skew(). + current_position[X_AXIS] = pgm_read_float(bed_ref_points + mesh_point * 2); + current_position[Y_AXIS] = pgm_read_float(bed_ref_points + mesh_point * 2 + 1); + go_to_current(homing_feedrate[X_AXIS] / 60); + delay_keep_alive(3000); + } + } + return result; + } + if (result == BED_SKEW_OFFSET_DETECTION_FITTING_FAILED && too_far_mask == 2) return result; //if fitting failed and front center point is out of reach, terminate calibration and inform user + iteration++; + } + return result; +} + +BedSkewOffsetDetectionResultType improve_bed_offset_and_skew(int8_t method, int8_t verbosity_level, uint8_t &too_far_mask) +{ + // Don't let the manage_inactivity() function remove power from the motors. + refresh_cmd_timeout(); + + // Mask of the first three points. Are they too far? + too_far_mask = 0; + + // Reusing the z_values memory for the measurement cache. + // 7x7=49 floats, good for 16 (x,y,z) vectors. + float *pts = &mbl.z_values[0][0]; + float *vec_x = pts + 2 * 9; + float *vec_y = vec_x + 2; + float *cntr = vec_y + 2; + memset(pts, 0, sizeof(float) * 7 * 7); + + if (verbosity_level >= 10) SERIAL_ECHOLNPGM("Improving bed offset and skew"); + + // Cache the current correction matrix. + world2machine_initialize(); + vec_x[0] = world2machine_rotation_and_skew[0][0]; + vec_x[1] = world2machine_rotation_and_skew[1][0]; + vec_y[0] = world2machine_rotation_and_skew[0][1]; + vec_y[1] = world2machine_rotation_and_skew[1][1]; + cntr[0] = world2machine_shift[0]; + cntr[1] = world2machine_shift[1]; + // and reset the correction matrix, so the planner will not do anything. + world2machine_reset(); + + bool endstops_enabled = enable_endstops(false); + bool endstop_z_enabled = enable_z_endstop(false); + +#ifdef MESH_BED_CALIBRATION_SHOW_LCD + uint8_t next_line; + lcd_display_message_fullscreen_P(MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1, next_line); + if (next_line > 3) + next_line = 3; +#endif /* MESH_BED_CALIBRATION_SHOW_LCD */ + + // Collect a matrix of 9x9 points. + BedSkewOffsetDetectionResultType result = BED_SKEW_OFFSET_DETECTION_PERFECT; + for (int8_t mesh_point = 0; mesh_point < 9; ++ mesh_point) { + // Don't let the manage_inactivity() function remove power from the motors. + refresh_cmd_timeout(); + // Print the decrasing ID of the measurement point. +#ifdef MESH_BED_CALIBRATION_SHOW_LCD + lcd_implementation_print_at(0, next_line, mesh_point+1); + lcd_printPGM(MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2); +#endif /* MESH_BED_CALIBRATION_SHOW_LCD */ + + // Move up. + current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; + enable_endstops(false); + enable_z_endstop(false); + go_to_current(homing_feedrate[Z_AXIS]/60); + if (verbosity_level >= 20) { + // Go to Y0, wait, then go to Y-4. + current_position[Y_AXIS] = 0.f; + go_to_current(homing_feedrate[X_AXIS] / 60.f); + SERIAL_ECHOLNPGM("At Y0"); + delay_keep_alive(5000); + current_position[Y_AXIS] = Y_MIN_POS; + go_to_current(homing_feedrate[X_AXIS] / 60.f); + SERIAL_ECHOLNPGM("At Y_MIN_POS"); + delay_keep_alive(5000); + } + // Go to the measurement point. + // Use the coorrected coordinate, which is a result of find_bed_offset_and_skew(). + current_position[X_AXIS] = vec_x[0] * pgm_read_float(bed_ref_points+mesh_point*2) + vec_y[0] * pgm_read_float(bed_ref_points+mesh_point*2+1) + cntr[0]; + current_position[Y_AXIS] = vec_x[1] * pgm_read_float(bed_ref_points+mesh_point*2) + vec_y[1] * pgm_read_float(bed_ref_points+mesh_point*2+1) + cntr[1]; + // The calibration points are very close to the min Y. + if (current_position[Y_AXIS] < Y_MIN_POS_FOR_BED_CALIBRATION){ + current_position[Y_AXIS] = Y_MIN_POS_FOR_BED_CALIBRATION; + if (verbosity_level >= 20) { + SERIAL_ECHOPGM("Calibration point "); + SERIAL_ECHO(mesh_point); + SERIAL_ECHOPGM("lower than Ymin. Y coordinate clamping was used."); + SERIAL_ECHOLNPGM(""); + } + } + go_to_current(homing_feedrate[X_AXIS]/60); + // Find its Z position by running the normal vertical search. + if (verbosity_level >= 10) + delay_keep_alive(3000); + find_bed_induction_sensor_point_z(); + if (verbosity_level >= 10) + delay_keep_alive(3000); + // Try to move the Z axis down a bit to increase a chance of the sensor to trigger. + current_position[Z_AXIS] -= 0.025f; + // Improve the point position by searching its center in a current plane. + int8_t n_errors = 3; + for (int8_t iter = 0; iter < 8; ) { + if (verbosity_level > 20) { + SERIAL_ECHOPGM("Improving bed point "); + SERIAL_ECHO(mesh_point); + SERIAL_ECHOPGM(", iteration "); + SERIAL_ECHO(iter); + SERIAL_ECHOPGM(", z"); + MYSERIAL.print(current_position[Z_AXIS], 5); + SERIAL_ECHOLNPGM(""); + } + bool found = false; + if (mesh_point < 3) { + // Because the sensor cannot move in front of the first row + // of the sensor points, the y position cannot be measured + // by a cross center method. + // Use a zig-zag search for the first row of the points. + found = improve_bed_induction_sensor_point3(verbosity_level); + } else { + switch (method) { + case 0: found = improve_bed_induction_sensor_point(); break; + case 1: found = improve_bed_induction_sensor_point2(mesh_point < 3, verbosity_level); break; + default: break; + } + } + if (found) { + if (iter > 3) { + // Average the last 4 measurements. + pts[mesh_point*2 ] += current_position[X_AXIS]; + pts[mesh_point*2+1] += current_position[Y_AXIS]; + } + if (current_position[Y_AXIS] < Y_MIN_POS) + current_position[Y_AXIS] = Y_MIN_POS; + ++ iter; + } else if (n_errors -- == 0) { + // Give up. + result = BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND; + goto canceled; + } else { + // Try to move the Z axis down a bit to increase a chance of the sensor to trigger. + current_position[Z_AXIS] -= 0.05f; + enable_endstops(false); + enable_z_endstop(false); + go_to_current(homing_feedrate[Z_AXIS]); + if (verbosity_level >= 5) { + SERIAL_ECHOPGM("Improving bed point "); + SERIAL_ECHO(mesh_point); + SERIAL_ECHOPGM(", iteration "); + SERIAL_ECHO(iter); + SERIAL_ECHOPGM(" failed. Lowering z to "); + MYSERIAL.print(current_position[Z_AXIS], 5); + SERIAL_ECHOLNPGM(""); + } + } + } + if (verbosity_level >= 10) + delay_keep_alive(3000); + } + // Don't let the manage_inactivity() function remove power from the motors. + refresh_cmd_timeout(); + + // Average the last 4 measurements. + for (int8_t i = 0; i < 18; ++ i) + pts[i] *= (1.f/4.f); + + enable_endstops(false); + enable_z_endstop(false); + + if (verbosity_level >= 5) { + // Test the positions. Are the positions reproducible? + current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; + for (int8_t mesh_point = 0; mesh_point < 9; ++ mesh_point) { + // Don't let the manage_inactivity() function remove power from the motors. + refresh_cmd_timeout(); + // Go to the measurement point. + // Use the coorrected coordinate, which is a result of find_bed_offset_and_skew(). + current_position[X_AXIS] = pts[mesh_point*2]; + current_position[Y_AXIS] = pts[mesh_point*2+1]; + if (verbosity_level >= 10) { + go_to_current(homing_feedrate[X_AXIS]/60); + delay_keep_alive(3000); + } + SERIAL_ECHOPGM("Final measured bed point "); + SERIAL_ECHO(mesh_point); + SERIAL_ECHOPGM(": "); + MYSERIAL.print(current_position[X_AXIS], 5); + SERIAL_ECHOPGM(", "); + MYSERIAL.print(current_position[Y_AXIS], 5); + SERIAL_ECHOLNPGM(""); + } + } + + { + // First fill in the too_far_mask from the measured points. + for (uint8_t mesh_point = 0; mesh_point < 3; ++ mesh_point) + if (pts[mesh_point * 2 + 1] < Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH) + too_far_mask |= 1 << mesh_point; + result = calculate_machine_skew_and_offset_LS(pts, 9, bed_ref_points, vec_x, vec_y, cntr, verbosity_level); + if (result < 0) { + SERIAL_ECHOLNPGM("Calculation of the machine skew and offset failed."); + goto canceled; + } + // In case of success, update the too_far_mask from the calculated points. + for (uint8_t mesh_point = 0; mesh_point < 3; ++ mesh_point) { + float y = vec_x[1] * pgm_read_float(bed_ref_points+mesh_point*2) + vec_y[1] * pgm_read_float(bed_ref_points+mesh_point*2+1) + cntr[1]; + distance_from_min[mesh_point] = (y - Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH); + if (verbosity_level >= 20) { + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("Distance from min:"); + MYSERIAL.print(distance_from_min[mesh_point]); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("y:"); + MYSERIAL.print(y); + SERIAL_ECHOLNPGM(""); + } + if (y < Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH) + too_far_mask |= 1 << mesh_point; + } + } + + world2machine_update(vec_x, vec_y, cntr); +#if 1 + // Fearlessly store the calibration values into the eeprom. + eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_CENTER+0), cntr [0]); + eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_CENTER+4), cntr [1]); + eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_X +0), vec_x[0]); + eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_X +4), vec_x[1]); + eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y +0), vec_y[0]); + eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y +4), vec_y[1]); +#endif + + // Correct the current_position to match the transformed coordinate system after world2machine_rotation_and_skew and world2machine_shift were set. + world2machine_update_current(); + + enable_endstops(false); + enable_z_endstop(false); + + if (verbosity_level >= 5) { + // Test the positions. Are the positions reproducible? Now the calibration is active in the planner. + delay_keep_alive(3000); + current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; + for (int8_t mesh_point = 0; mesh_point < 9; ++ mesh_point) { + // Don't let the manage_inactivity() function remove power from the motors. + refresh_cmd_timeout(); + // Go to the measurement point. + // Use the coorrected coordinate, which is a result of find_bed_offset_and_skew(). + current_position[X_AXIS] = pgm_read_float(bed_ref_points+mesh_point*2); + current_position[Y_AXIS] = pgm_read_float(bed_ref_points+mesh_point*2+1); + if (verbosity_level >= 10) { + go_to_current(homing_feedrate[X_AXIS]/60); + delay_keep_alive(3000); + } + { + float x, y; + world2machine(current_position[X_AXIS], current_position[Y_AXIS], x, y); + SERIAL_ECHOPGM("Final calculated bed point "); + SERIAL_ECHO(mesh_point); + SERIAL_ECHOPGM(": "); + MYSERIAL.print(x, 5); + SERIAL_ECHOPGM(", "); + MYSERIAL.print(y, 5); + SERIAL_ECHOLNPGM(""); + } + } + } + + // Sample Z heights for the mesh bed leveling. + // In addition, store the results into an eeprom, to be used later for verification of the bed leveling process. + if (! sample_mesh_and_store_reference()) + goto canceled; + + enable_endstops(endstops_enabled); + enable_z_endstop(endstop_z_enabled); + // Don't let the manage_inactivity() function remove power from the motors. + refresh_cmd_timeout(); + return result; + +canceled: + // Don't let the manage_inactivity() function remove power from the motors. + refresh_cmd_timeout(); + // Print head up. + current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; + go_to_current(homing_feedrate[Z_AXIS]/60); + // Store the identity matrix to EEPROM. + reset_bed_offset_and_skew(); + enable_endstops(endstops_enabled); + enable_z_endstop(endstop_z_enabled); + return result; +} + +void go_home_with_z_lift() +{ + // Don't let the manage_inactivity() function remove power from the motors. + refresh_cmd_timeout(); + // Go home. + // First move up to a safe height. + current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; + go_to_current(homing_feedrate[Z_AXIS]/60); + // Second move to XY [0, 0]. + current_position[X_AXIS] = X_MIN_POS+0.2; + current_position[Y_AXIS] = Y_MIN_POS+0.2; + // Clamp to the physical coordinates. + world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]); + go_to_current(homing_feedrate[X_AXIS]/60); + // Third move up to a safe height. + current_position[Z_AXIS] = Z_MIN_POS; + go_to_current(homing_feedrate[Z_AXIS]/60); +} + +// Sample the 9 points of the bed and store them into the EEPROM as a reference. +// When calling this function, the X, Y, Z axes should be already homed, +// and the world2machine correction matrix should be active. +// Returns false if the reference values are more than 3mm far away. +bool sample_mesh_and_store_reference() +{ + bool endstops_enabled = enable_endstops(false); + bool endstop_z_enabled = enable_z_endstop(false); + + // Don't let the manage_inactivity() function remove power from the motors. + refresh_cmd_timeout(); + +#ifdef MESH_BED_CALIBRATION_SHOW_LCD + uint8_t next_line; + lcd_display_message_fullscreen_P(MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1, next_line); + if (next_line > 3) + next_line = 3; + // display "point xx of yy" + lcd_implementation_print_at(0, next_line, 1); + lcd_printPGM(MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2); +#endif /* MESH_BED_CALIBRATION_SHOW_LCD */ + + // Sample Z heights for the mesh bed leveling. + // In addition, store the results into an eeprom, to be used later for verification of the bed leveling process. + { + // The first point defines the reference. + current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; + go_to_current(homing_feedrate[Z_AXIS]/60); + current_position[X_AXIS] = pgm_read_float(bed_ref_points); + current_position[Y_AXIS] = pgm_read_float(bed_ref_points+1); + world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]); + go_to_current(homing_feedrate[X_AXIS]/60); + memcpy(destination, current_position, sizeof(destination)); + enable_endstops(true); + homeaxis(Z_AXIS); + enable_endstops(false); + find_bed_induction_sensor_point_z(); + mbl.set_z(0, 0, current_position[Z_AXIS]); + } + for (int8_t mesh_point = 1; mesh_point != MESH_MEAS_NUM_X_POINTS * MESH_MEAS_NUM_Y_POINTS; ++ mesh_point) { + // Don't let the manage_inactivity() function remove power from the motors. + refresh_cmd_timeout(); + // Print the decrasing ID of the measurement point. + current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; + go_to_current(homing_feedrate[Z_AXIS]/60); + current_position[X_AXIS] = pgm_read_float(bed_ref_points+2*mesh_point); + current_position[Y_AXIS] = pgm_read_float(bed_ref_points+2*mesh_point+1); + world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]); + go_to_current(homing_feedrate[X_AXIS]/60); +#ifdef MESH_BED_CALIBRATION_SHOW_LCD + // display "point xx of yy" + lcd_implementation_print_at(0, next_line, mesh_point+1); + lcd_printPGM(MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2); +#endif /* MESH_BED_CALIBRATION_SHOW_LCD */ + find_bed_induction_sensor_point_z(); + // Get cords of measuring point + int8_t ix = mesh_point % MESH_MEAS_NUM_X_POINTS; + int8_t iy = mesh_point / MESH_MEAS_NUM_X_POINTS; + if (iy & 1) ix = (MESH_MEAS_NUM_X_POINTS - 1) - ix; // Zig zag + mbl.set_z(ix, iy, current_position[Z_AXIS]); + } + { + // Verify the span of the Z values. + float zmin = mbl.z_values[0][0]; + float zmax = zmax; + for (int8_t j = 0; j < 3; ++ j) + for (int8_t i = 0; i < 3; ++ i) { + zmin = min(zmin, mbl.z_values[j][i]); + zmax = min(zmax, mbl.z_values[j][i]); + } + if (zmax - zmin > 3.f) { + // The span of the Z offsets is extreme. Give up. + // Homing failed on some of the points. + SERIAL_PROTOCOLLNPGM("Exreme span of the Z values!"); + return false; + } + } + + // Store the correction values to EEPROM. + // Offsets of the Z heiths of the calibration points from the first point. + // The offsets are saved as 16bit signed int, scaled to tenths of microns. + { + uint16_t addr = EEPROM_BED_CALIBRATION_Z_JITTER; + for (int8_t j = 0; j < 3; ++ j) + for (int8_t i = 0; i < 3; ++ i) { + if (i == 0 && j == 0) + continue; + float dif = mbl.z_values[j][i] - mbl.z_values[0][0]; + int16_t dif_quantized = int16_t(floor(dif * 100.f + 0.5f)); + eeprom_update_word((uint16_t*)addr, *reinterpret_cast(&dif_quantized)); + #if 0 + { + uint16_t z_offset_u = eeprom_read_word((uint16_t*)addr); + float dif2 = *reinterpret_cast(&z_offset_u) * 0.01; + + SERIAL_ECHOPGM("Bed point "); + SERIAL_ECHO(i); + SERIAL_ECHOPGM(","); + SERIAL_ECHO(j); + SERIAL_ECHOPGM(", differences: written "); + MYSERIAL.print(dif, 5); + SERIAL_ECHOPGM(", read: "); + MYSERIAL.print(dif2, 5); + SERIAL_ECHOLNPGM(""); + } + #endif + addr += 2; + } + } + + mbl.upsample_3x3(); + mbl.active = true; + + go_home_with_z_lift(); + + enable_endstops(endstops_enabled); + enable_z_endstop(endstop_z_enabled); + return true; +} + +bool scan_bed_induction_points(int8_t verbosity_level) +{ + // Don't let the manage_inactivity() function remove power from the motors. + refresh_cmd_timeout(); + + // Reusing the z_values memory for the measurement cache. + // 7x7=49 floats, good for 16 (x,y,z) vectors. + float *pts = &mbl.z_values[0][0]; + float *vec_x = pts + 2 * 9; + float *vec_y = vec_x + 2; + float *cntr = vec_y + 2; + memset(pts, 0, sizeof(float) * 7 * 7); + + // Cache the current correction matrix. + world2machine_initialize(); + vec_x[0] = world2machine_rotation_and_skew[0][0]; + vec_x[1] = world2machine_rotation_and_skew[1][0]; + vec_y[0] = world2machine_rotation_and_skew[0][1]; + vec_y[1] = world2machine_rotation_and_skew[1][1]; + cntr[0] = world2machine_shift[0]; + cntr[1] = world2machine_shift[1]; + // and reset the correction matrix, so the planner will not do anything. + world2machine_reset(); + + bool endstops_enabled = enable_endstops(false); + bool endstop_z_enabled = enable_z_endstop(false); + + // Collect a matrix of 9x9 points. + for (int8_t mesh_point = 0; mesh_point < 9; ++ mesh_point) { + // Don't let the manage_inactivity() function remove power from the motors. + refresh_cmd_timeout(); + + // Move up. + current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; + enable_endstops(false); + enable_z_endstop(false); + go_to_current(homing_feedrate[Z_AXIS]/60); + // Go to the measurement point. + // Use the coorrected coordinate, which is a result of find_bed_offset_and_skew(). + current_position[X_AXIS] = vec_x[0] * pgm_read_float(bed_ref_points+mesh_point*2) + vec_y[0] * pgm_read_float(bed_ref_points+mesh_point*2+1) + cntr[0]; + current_position[Y_AXIS] = vec_x[1] * pgm_read_float(bed_ref_points+mesh_point*2) + vec_y[1] * pgm_read_float(bed_ref_points+mesh_point*2+1) + cntr[1]; + // The calibration points are very close to the min Y. + if (current_position[Y_AXIS] < Y_MIN_POS_FOR_BED_CALIBRATION) + current_position[Y_AXIS] = Y_MIN_POS_FOR_BED_CALIBRATION; + go_to_current(homing_feedrate[X_AXIS]/60); + find_bed_induction_sensor_point_z(); + scan_bed_induction_sensor_point(); + } + // Don't let the manage_inactivity() function remove power from the motors. + refresh_cmd_timeout(); + + enable_endstops(false); + enable_z_endstop(false); + + // Don't let the manage_inactivity() function remove power from the motors. + refresh_cmd_timeout(); + + enable_endstops(endstops_enabled); + enable_z_endstop(endstop_z_enabled); + return true; +} + +// Shift a Z axis by a given delta. +// To replace loading of the babystep correction. +static void shift_z(float delta) +{ + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] - delta, current_position[E_AXIS], homing_feedrate[Z_AXIS]/40, active_extruder); + st_synchronize(); + plan_set_z_position(current_position[Z_AXIS]); +} + +#define BABYSTEP_LOADZ_BY_PLANNER + +// Number of baby steps applied +static int babystepLoadZ = 0; + +void babystep_apply() +{ + // Apply Z height correction aka baby stepping before mesh bed leveling gets activated. + if(calibration_status() < CALIBRATION_STATUS_LIVE_ADJUST) + { + check_babystep(); //checking if babystep is in allowed range, otherwise setting babystep to 0 + + // End of G80: Apply the baby stepping value. + EEPROM_read_B(EEPROM_BABYSTEP_Z,&babystepLoadZ); + + #if 0 + SERIAL_ECHO("Z baby step: "); + SERIAL_ECHO(babystepLoadZ); + SERIAL_ECHO(", current Z: "); + SERIAL_ECHO(current_position[Z_AXIS]); + SERIAL_ECHO("correction: "); + SERIAL_ECHO(float(babystepLoadZ) / float(axis_steps_per_unit[Z_AXIS])); + SERIAL_ECHOLN(""); + #endif + #ifdef BABYSTEP_LOADZ_BY_PLANNER + shift_z(- float(babystepLoadZ) / float(axis_steps_per_unit[Z_AXIS])); + #else + babystepsTodoZadd(babystepLoadZ); + #endif /* BABYSTEP_LOADZ_BY_PLANNER */ + } +} + +void babystep_undo() +{ +#ifdef BABYSTEP_LOADZ_BY_PLANNER + shift_z(float(babystepLoadZ) / float(axis_steps_per_unit[Z_AXIS])); +#else + babystepsTodoZsubtract(babystepLoadZ); +#endif /* BABYSTEP_LOADZ_BY_PLANNER */ + babystepLoadZ = 0; +} + +void babystep_reset() +{ + babystepLoadZ = 0; +} + +void count_xyz_details() { + float a1, a2; + float cntr[2] = { + eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_CENTER + 0)), + eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_CENTER + 4)) + }; + float vec_x[2] = { + eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_X + 0)), + eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_X + 4)) + }; + float vec_y[2] = { + eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y + 0)), + eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y + 4)) + }; + a2 = -1 * asin(vec_y[0] / MACHINE_AXIS_SCALE_Y); + a1 = asin(vec_x[1] / MACHINE_AXIS_SCALE_X); + angleDiff = fabs(a2 - a1); + for (uint8_t mesh_point = 0; mesh_point < 3; ++mesh_point) { + float y = vec_x[1] * pgm_read_float(bed_ref_points + mesh_point * 2) + vec_y[1] * pgm_read_float(bed_ref_points + mesh_point * 2 + 1) + cntr[1]; + distance_from_min[mesh_point] = (y - Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH); + } +} + +/*countDistanceFromMin() { + +}*/ + + + diff --git a/Firmware/mesh_bed_calibration.h b/Firmware/mesh_bed_calibration.h index 102fa48dd..5fe7dcece 100644 --- a/Firmware/mesh_bed_calibration.h +++ b/Firmware/mesh_bed_calibration.h @@ -1,182 +1,186 @@ -#ifndef MESH_BED_CALIBRATION_H -#define MESH_BED_CALIBRATION_H - -// Exact positions of the print head above the bed reference points, in the world coordinates. -// The world coordinates match the machine coordinates only in case, when the machine -// is built properly, the end stops are at the correct positions and the axes are perpendicular. -extern const float bed_ref_points[] PROGMEM; - -// Is the world2machine correction activated? -enum World2MachineCorrectionMode -{ - WORLD2MACHINE_CORRECTION_NONE = 0, - WORLD2MACHINE_CORRECTION_SHIFT = 1, - WORLD2MACHINE_CORRECTION_SKEW = 2, -}; -extern uint8_t world2machine_correction_mode; -// 2x2 transformation matrix from the world coordinates to the machine coordinates. -// Corrects for the rotation and skew of the machine axes. -// Used by the planner's plan_buffer_line() and plan_set_position(). -extern float world2machine_rotation_and_skew[2][2]; -extern float world2machine_rotation_and_skew_inv[2][2]; -// Shift of the machine zero point, in the machine coordinates. -extern float world2machine_shift[2]; - -// Resets the transformation to identity. -extern void world2machine_reset(); -// Resets the transformation to identity and update current_position[X,Y] from the servos. -extern void world2machine_revert_to_uncorrected(); -// Loads the transformation from the EEPROM, if available. -extern void world2machine_initialize(); - -// When switching from absolute to corrected coordinates, -// this will apply an inverse world2machine transformation -// to current_position[x,y]. -extern void world2machine_update_current(); - -inline void world2machine(const float &x, const float &y, float &out_x, float &out_y) -{ - if (world2machine_correction_mode == WORLD2MACHINE_CORRECTION_NONE) { - // No correction. - out_x = x; - out_y = y; - } else { - if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SKEW) { - // Firs the skew & rotation correction. - out_x = world2machine_rotation_and_skew[0][0] * x + world2machine_rotation_and_skew[0][1] * y; - out_y = world2machine_rotation_and_skew[1][0] * x + world2machine_rotation_and_skew[1][1] * y; - } - if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SHIFT) { - // Then add the offset. - out_x += world2machine_shift[0]; - out_y += world2machine_shift[1]; - } - } -} - -inline void world2machine(float &x, float &y) -{ - if (world2machine_correction_mode == WORLD2MACHINE_CORRECTION_NONE) { - // No correction. - } else { - if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SKEW) { - // Firs the skew & rotation correction. - float out_x = world2machine_rotation_and_skew[0][0] * x + world2machine_rotation_and_skew[0][1] * y; - float out_y = world2machine_rotation_and_skew[1][0] * x + world2machine_rotation_and_skew[1][1] * y; - x = out_x; - y = out_y; - } - if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SHIFT) { - // Then add the offset. - x += world2machine_shift[0]; - y += world2machine_shift[1]; - } - } -} - -inline void machine2world(float x, float y, float &out_x, float &out_y) -{ - if (world2machine_correction_mode == WORLD2MACHINE_CORRECTION_NONE) { - // No correction. - out_x = x; - out_y = y; - } else { - if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SHIFT) { - // Then add the offset. - x -= world2machine_shift[0]; - y -= world2machine_shift[1]; - } - if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SKEW) { - // Firs the skew & rotation correction. - out_x = world2machine_rotation_and_skew_inv[0][0] * x + world2machine_rotation_and_skew_inv[0][1] * y; - out_y = world2machine_rotation_and_skew_inv[1][0] * x + world2machine_rotation_and_skew_inv[1][1] * y; - } - } -} - -inline void machine2world(float &x, float &y) -{ - if (world2machine_correction_mode == WORLD2MACHINE_CORRECTION_NONE) { - // No correction. - } else { - if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SHIFT) { - // Then add the offset. - x -= world2machine_shift[0]; - y -= world2machine_shift[1]; - } - if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SKEW) { - // Firs the skew & rotation correction. - float out_x = world2machine_rotation_and_skew_inv[0][0] * x + world2machine_rotation_and_skew_inv[0][1] * y; - float out_y = world2machine_rotation_and_skew_inv[1][0] * x + world2machine_rotation_and_skew_inv[1][1] * y; - x = out_x; - y = out_y; - } - } -} - -inline bool world2machine_clamp(float &x, float &y) -{ - bool clamped = false; - float tmpx, tmpy; - world2machine(x, y, tmpx, tmpy); - if (tmpx < X_MIN_POS) { - tmpx = X_MIN_POS; - clamped = true; - } - if (tmpy < Y_MIN_POS) { - tmpy = Y_MIN_POS; - clamped = true; - } - if (tmpx > X_MAX_POS) { - tmpx = X_MAX_POS; - clamped = true; - } - if (tmpy > Y_MAX_POS) { - tmpy = Y_MAX_POS; - clamped = true; - } - if (clamped) - machine2world(tmpx, tmpy, x, y); - return clamped; -} - -extern bool find_bed_induction_sensor_point_z(float minimum_z = -10.f, uint8_t n_iter = 3); -extern bool find_bed_induction_sensor_point_xy(); -extern void go_home_with_z_lift(); - -// Positive or zero: ok -// Negative: failed -enum BedSkewOffsetDetectionResultType { - // Detection failed, some point was not found. - BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND = -1, - BED_SKEW_OFFSET_DETECTION_FITTING_FAILED = -2, - - // Detection finished with success. - BED_SKEW_OFFSET_DETECTION_PERFECT = 0, - BED_SKEW_OFFSET_DETECTION_SKEW_MILD = 1, - BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME = 2 -}; - -extern BedSkewOffsetDetectionResultType find_bed_offset_and_skew(int8_t verbosity_level); -extern BedSkewOffsetDetectionResultType improve_bed_offset_and_skew(int8_t method, int8_t verbosity_level, uint8_t &too_far_mask); - -extern bool sample_mesh_and_store_reference(); - -extern void reset_bed_offset_and_skew(); -extern bool is_bed_z_jitter_data_valid(); - -// Scan the mesh bed induction points one by one by a left-right zig-zag movement, -// write the trigger coordinates to the serial line. -// Useful for visualizing the behavior of the bed induction detector. -extern bool scan_bed_induction_points(int8_t verbosity_level); - -// Apply Z babystep value from the EEPROM through the planner. -extern void babystep_apply(); - -// Undo the current Z babystep value. -extern void babystep_undo(); - -// Reset the current babystep counter without moving the axes. -extern void babystep_reset(); - -#endif /* MESH_BED_CALIBRATION_H */ +#ifndef MESH_BED_CALIBRATION_H +#define MESH_BED_CALIBRATION_H + +// Exact positions of the print head above the bed reference points, in the world coordinates. +// The world coordinates match the machine coordinates only in case, when the machine +// is built properly, the end stops are at the correct positions and the axes are perpendicular. +extern const float bed_ref_points[] PROGMEM; + +extern const float bed_skew_angle_mild; +extern const float bed_skew_angle_extreme; + +// Is the world2machine correction activated? +enum World2MachineCorrectionMode +{ + WORLD2MACHINE_CORRECTION_NONE = 0, + WORLD2MACHINE_CORRECTION_SHIFT = 1, + WORLD2MACHINE_CORRECTION_SKEW = 2, +}; +extern uint8_t world2machine_correction_mode; +// 2x2 transformation matrix from the world coordinates to the machine coordinates. +// Corrects for the rotation and skew of the machine axes. +// Used by the planner's plan_buffer_line() and plan_set_position(). +extern float world2machine_rotation_and_skew[2][2]; +extern float world2machine_rotation_and_skew_inv[2][2]; +// Shift of the machine zero point, in the machine coordinates. +extern float world2machine_shift[2]; + +// Resets the transformation to identity. +extern void world2machine_reset(); +// Resets the transformation to identity and update current_position[X,Y] from the servos. +extern void world2machine_revert_to_uncorrected(); +// Loads the transformation from the EEPROM, if available. +extern void world2machine_initialize(); + +// When switching from absolute to corrected coordinates, +// this will apply an inverse world2machine transformation +// to current_position[x,y]. +extern void world2machine_update_current(); + +inline void world2machine(const float &x, const float &y, float &out_x, float &out_y) +{ + if (world2machine_correction_mode == WORLD2MACHINE_CORRECTION_NONE) { + // No correction. + out_x = x; + out_y = y; + } else { + if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SKEW) { + // Firs the skew & rotation correction. + out_x = world2machine_rotation_and_skew[0][0] * x + world2machine_rotation_and_skew[0][1] * y; + out_y = world2machine_rotation_and_skew[1][0] * x + world2machine_rotation_and_skew[1][1] * y; + } + if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SHIFT) { + // Then add the offset. + out_x += world2machine_shift[0]; + out_y += world2machine_shift[1]; + } + } +} + +inline void world2machine(float &x, float &y) +{ + if (world2machine_correction_mode == WORLD2MACHINE_CORRECTION_NONE) { + // No correction. + } else { + if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SKEW) { + // Firs the skew & rotation correction. + float out_x = world2machine_rotation_and_skew[0][0] * x + world2machine_rotation_and_skew[0][1] * y; + float out_y = world2machine_rotation_and_skew[1][0] * x + world2machine_rotation_and_skew[1][1] * y; + x = out_x; + y = out_y; + } + if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SHIFT) { + // Then add the offset. + x += world2machine_shift[0]; + y += world2machine_shift[1]; + } + } +} + +inline void machine2world(float x, float y, float &out_x, float &out_y) +{ + if (world2machine_correction_mode == WORLD2MACHINE_CORRECTION_NONE) { + // No correction. + out_x = x; + out_y = y; + } else { + if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SHIFT) { + // Then add the offset. + x -= world2machine_shift[0]; + y -= world2machine_shift[1]; + } + if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SKEW) { + // Firs the skew & rotation correction. + out_x = world2machine_rotation_and_skew_inv[0][0] * x + world2machine_rotation_and_skew_inv[0][1] * y; + out_y = world2machine_rotation_and_skew_inv[1][0] * x + world2machine_rotation_and_skew_inv[1][1] * y; + } + } +} + +inline void machine2world(float &x, float &y) +{ + if (world2machine_correction_mode == WORLD2MACHINE_CORRECTION_NONE) { + // No correction. + } else { + if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SHIFT) { + // Then add the offset. + x -= world2machine_shift[0]; + y -= world2machine_shift[1]; + } + if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SKEW) { + // Firs the skew & rotation correction. + float out_x = world2machine_rotation_and_skew_inv[0][0] * x + world2machine_rotation_and_skew_inv[0][1] * y; + float out_y = world2machine_rotation_and_skew_inv[1][0] * x + world2machine_rotation_and_skew_inv[1][1] * y; + x = out_x; + y = out_y; + } + } +} + +inline bool world2machine_clamp(float &x, float &y) +{ + bool clamped = false; + float tmpx, tmpy; + world2machine(x, y, tmpx, tmpy); + if (tmpx < X_MIN_POS) { + tmpx = X_MIN_POS; + clamped = true; + } + if (tmpy < Y_MIN_POS) { + tmpy = Y_MIN_POS; + clamped = true; + } + if (tmpx > X_MAX_POS) { + tmpx = X_MAX_POS; + clamped = true; + } + if (tmpy > Y_MAX_POS) { + tmpy = Y_MAX_POS; + clamped = true; + } + if (clamped) + machine2world(tmpx, tmpy, x, y); + return clamped; +} + +extern bool find_bed_induction_sensor_point_z(float minimum_z = -10.f, uint8_t n_iter = 3, int verbosity_level = 0); +extern bool find_bed_induction_sensor_point_xy(int verbosity_level = 0); +extern void go_home_with_z_lift(); + +// Positive or zero: ok +// Negative: failed +enum BedSkewOffsetDetectionResultType { + // Detection failed, some point was not found. + BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND = -1, + BED_SKEW_OFFSET_DETECTION_FITTING_FAILED = -2, + + // Detection finished with success. + BED_SKEW_OFFSET_DETECTION_PERFECT = 0, + BED_SKEW_OFFSET_DETECTION_SKEW_MILD = 1, + BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME = 2 +}; + +extern BedSkewOffsetDetectionResultType find_bed_offset_and_skew(int8_t verbosity_level, uint8_t &too_far_mask); +extern BedSkewOffsetDetectionResultType improve_bed_offset_and_skew(int8_t method, int8_t verbosity_level, uint8_t &too_far_mask); + +extern bool sample_mesh_and_store_reference(); + +extern void reset_bed_offset_and_skew(); +extern bool is_bed_z_jitter_data_valid(); + +// Scan the mesh bed induction points one by one by a left-right zig-zag movement, +// write the trigger coordinates to the serial line. +// Useful for visualizing the behavior of the bed induction detector. +extern bool scan_bed_induction_points(int8_t verbosity_level); + +// Apply Z babystep value from the EEPROM through the planner. +extern void babystep_apply(); + +// Undo the current Z babystep value. +extern void babystep_undo(); + +// Reset the current babystep counter without moving the axes. +extern void babystep_reset(); +extern void count_xyz_details(); + +#endif /* MESH_BED_CALIBRATION_H */ diff --git a/Firmware/pins.h b/Firmware/pins.h index b043b49b5..1ed3958be 100644 --- a/Firmware/pins.h +++ b/Firmware/pins.h @@ -315,12 +315,9 @@ #endif - - - /***************************************************************** - * EINY Rambo Pin Assignments 0.1a - ******************************************************************/ +* EINY Rambo Pin Assignments 0.1a +******************************************************************/ #if MOTHERBOARD == 300 #define ELECTRONICS "EINY_01a" #define KNOWN_BOARD @@ -427,7 +424,6 @@ - #ifndef KNOWN_BOARD #error Unknown MOTHERBOARD value in configuration.h #endif diff --git a/Firmware/planner.h b/Firmware/planner.h index a13aa1bd2..30194952d 100644 --- a/Firmware/planner.h +++ b/Firmware/planner.h @@ -171,7 +171,9 @@ FORCE_INLINE block_t *plan_get_current_block() } // Returns true if the buffer has a queued block, false otherwise -FORCE_INLINE bool blocks_queued() { return (block_buffer_head != block_buffer_tail); } +FORCE_INLINE bool blocks_queued() { + return (block_buffer_head != block_buffer_tail); +} //return the nr of buffered moves FORCE_INLINE uint8_t moves_planned() { diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index 1b1ce9142..4cadd180e 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -33,8 +33,9 @@ #include #endif #ifdef HAVE_TMC2130_DRIVERS -#include -#endif +#include "tmc2130.h" +#endif //HAVE_TMC2130_DRIVERS + //=========================================================================== //=============================public variables ============================ @@ -83,17 +84,12 @@ static bool old_z_min_endstop=false; static bool old_z_max_endstop=false; #ifdef SG_HOMING - static bool check_endstops = false; +static bool check_endstops = false; #else - static bool check_endstops = true; +static bool check_endstops = true; #endif - static bool check_z_endstop = false; -static uint8_t sg_homing_axis = 0xFF; -static uint8_t sg_axis_stalled[2] = {0, 0}; -static uint8_t sg_lastHomingStalled = false; - int8_t SilentMode; volatile long count_position[NUM_AXIS] = { 0, 0, 0, 0}; @@ -408,11 +404,6 @@ ISR(TIMER1_COMPA_vect) { #if defined(X_MIN_PIN) && X_MIN_PIN > -1 bool x_min_endstop=(READ(X_MIN_PIN) != X_MIN_ENDSTOP_INVERTING); - #ifdef SG_HOMING - x_min_endstop=false; - #endif - if(sg_homing_axis == X_AXIS && !x_min_endstop) - x_min_endstop = sg_axis_stalled[X_AXIS]; if(x_min_endstop && old_x_min_endstop && (current_block->steps_x > 0)) { endstops_trigsteps[X_AXIS] = count_position[X_AXIS]; endstop_x_hit=true; @@ -429,8 +420,6 @@ ISR(TIMER1_COMPA_vect) { #if defined(X_MAX_PIN) && X_MAX_PIN > -1 bool x_max_endstop=(READ(X_MAX_PIN) != X_MAX_ENDSTOP_INVERTING); - if(sg_homing_axis == X_AXIS && !x_max_endstop) - x_max_endstop = sg_axis_stalled[X_AXIS]; if(x_max_endstop && old_x_max_endstop && (current_block->steps_x > 0)){ endstops_trigsteps[X_AXIS] = count_position[X_AXIS]; endstop_x_hit=true; @@ -451,11 +440,6 @@ ISR(TIMER1_COMPA_vect) { #if defined(Y_MIN_PIN) && Y_MIN_PIN > -1 bool y_min_endstop=(READ(Y_MIN_PIN) != Y_MIN_ENDSTOP_INVERTING); - #ifdef SG_HOMING - y_min_endstop=false; - #endif - if(sg_homing_axis == Y_AXIS && !y_min_endstop) - y_min_endstop = sg_axis_stalled[Y_AXIS]; if(y_min_endstop && old_y_min_endstop && (current_block->steps_y > 0)) { endstops_trigsteps[Y_AXIS] = count_position[Y_AXIS]; endstop_y_hit=true; @@ -470,8 +454,6 @@ ISR(TIMER1_COMPA_vect) { #if defined(Y_MAX_PIN) && Y_MAX_PIN > -1 bool y_max_endstop=(READ(Y_MAX_PIN) != Y_MAX_ENDSTOP_INVERTING); - if(sg_homing_axis == Y_AXIS && !y_max_endstop) - y_max_endstop = sg_axis_stalled[Y_AXIS]; if(y_max_endstop && old_y_max_endstop && (current_block->steps_y > 0)){ endstops_trigsteps[Y_AXIS] = count_position[Y_AXIS]; endstop_y_hit=true; @@ -540,14 +522,39 @@ ISR(TIMER1_COMPA_vect) } #endif - if ((out_bits & (1< For better readability changed to 0x00 and added PWMautoScale and PWMfreq - } - - void tmc2130_PWMthreshold(uint8_t cs) - { - tmc2130_write(cs,0x13,0x00,0x00,0x00,0x00); // TMC LJ -> Adds possibility to swtich from stealthChop to spreadCycle automatically - } - - - void st_setSGHoming(uint8_t axis){ - sg_homing_axis = axis; - } - - void st_resetSGflags(){ - sg_axis_stalled[X_AXIS] = false; - sg_axis_stalled[Y_AXIS] = false; - } - - uint8_t st_didLastHomingStall(){ - uint8_t returnValue = sg_lastHomingStalled; - sg_lastHomingStalled = false; - return returnValue; - } - - - void tmc2130_disable_motor(uint8_t driver) - { - uint8_t cs[4] = { X_TMC2130_CS, Y_TMC2130_CS, Z_TMC2130_CS, E0_TMC2130_CS }; - tmc2130_write(cs[driver],0x6C,0,01,0,0); - } - - void tmc2130_check_overtemp() - { - const static char TMC_OVERTEMP_MSG[] PROGMEM = "TMC DRIVER OVERTEMP "; - uint8_t cs[4] = { X_TMC2130_CS, Y_TMC2130_CS, Z_TMC2130_CS, E0_TMC2130_CS }; - static uint32_t checktime = 0; - //drivers_disabled[0] = 1; //TEST - - if( millis() - checktime > 1000 ) { - for(int i=0;i<4;i++) { - uint32_t drv_status = tmc2130_read(cs[i], 0x6F); //0x6F DRV_STATUS - - if(drv_status & ((uint32_t)1<<26)) { // BIT 26 - over temp prewarning ~120C (+-20C) - SERIAL_ERRORRPGM(TMC_OVERTEMP_MSG); - SERIAL_ECHOLN(i); - - for(int x=0; x<4;x++) tmc2130_disable_motor(x); - kill(TMC_OVERTEMP_MSG); - } - } - - checktime = millis(); - } - } - -#endif //HAVE_TMC2130_DRIVERS - - void tmc2130_init() - { -#ifdef HAVE_TMC2130_DRIVERS - uint8_t cs[4] = { X_TMC2130_CS, Y_TMC2130_CS, Z_TMC2130_CS, E0_TMC2130_CS }; - uint8_t current[4] = { 31, 31, 31, 31 }; - - WRITE(X_TMC2130_CS, HIGH); - WRITE(Y_TMC2130_CS, HIGH); - WRITE(Z_TMC2130_CS, HIGH); - WRITE(E0_TMC2130_CS, HIGH); - SET_OUTPUT(X_TMC2130_CS); - SET_OUTPUT(Y_TMC2130_CS); - SET_OUTPUT(Z_TMC2130_CS); - SET_OUTPUT(E0_TMC2130_CS); - - SPI.begin(); - - for(int i=0;i<4;i++) - { - //tmc2130_write(cs[i],0x6C,0b10100,01,00,0xC5); - tmc2130_chopconf(cs[i],1,16); - tmc2130_write(cs[i],0x10,0,15,current[i],current[i]); //0x10 IHOLD_IRUN - //tmc2130_write(cs[i],0x0,0,0,0,0x05); //address=0x0 GCONF EXT VREF - tmc2130_write(cs[i],0x0,0,0,0,0x05); //address=0x0 GCONF EXT VREF - activate stealthChop - //tmc2130_write(cs[i],0x11,0,0,0,0xA); - - // Uncomment lines below to use a different configuration (pwm_autoscale = 0) for XY axes - // if(i==0 || i==1) - // tmc2130_PWMconf(cs[i],PWM_AUTOSCALE_XY,PWM_FREQ_XY,PWM_GRAD_XY,PWM_AMPL_XY); //address=0x70 PWM_CONF //reset default=0x00050480 - // else - tmc2130_PWMconf(cs[i]); //address=0x70 PWM_CONF //reset default=0x00050480 - tmc2130_PWMthreshold(cs[i]); - } - tmc2130_chopconf(cs[3],0,256); -#endif - } - - - void st_init() { - tmc2130_init(); //Initialize TMC2130 drivers +#ifdef HAVE_TMC2130_DRIVERS + tmc2130_init(); +#endif //HAVE_TMC2130_DRIVERS + digipot_init(); //Initialize Digipot Motor Current microstep_init(); //Initialize Microstepping Pins @@ -1164,53 +864,14 @@ void st_init() // Block until all buffered steps are executed void st_synchronize() { - uint8_t delay = 0; - while( blocks_queued()) { - manage_heater(); - // Vojtech: Don't disable motors inside the planner! - manage_inactivity(true); - lcd_update(); - - if(sg_homing_axis == X_AXIS || sg_homing_axis == Y_AXIS) - { - uint8_t axis; - if(sg_homing_axis == X_AXIS) - axis = X_TMC2130_CS; - else - axis = Y_TMC2130_CS; - - uint16_t tstep = tmc2130_readTStep(axis); - // SERIAL_PROTOCOLLN(tstep); - - if(tstep < TCOOLTHRS) - { - if(delay < 255) // wait for a few tens microsteps until stallGuard is used //todo: read out microsteps directly, instead of delay counter - delay++; - else - { - uint16_t sg = tmc2130_readSG(axis); - if(sg==0) - { - sg_axis_stalled[sg_homing_axis] = true; - sg_lastHomingStalled = true; - } - else - sg_axis_stalled[sg_homing_axis] = false; - // SERIAL_PROTOCOLLN(sg); - } - } - else - { - sg_axis_stalled[sg_homing_axis] = false; - delay = 0; - } - - } - else - { - sg_axis_stalled[X_AXIS] = false; - sg_axis_stalled[Y_AXIS] = false; - } + while( blocks_queued()) { + manage_heater(); + // Vojtech: Don't disable motors inside the planner! + manage_inactivity(true); + lcd_update(); +#ifdef HAVE_TMC2130_DRIVERS + tmc2130_st_synchronize(); +#endif //HAVE_TMC2130_DRIVERS } } @@ -1518,9 +1179,10 @@ static void check_fans() { fan_edge_counter[0] ++; fan_state[0] = READ(TACH_0); } - if (READ(TACH_1) != fan_state[1]){ + if (READ(TACH_1) != fan_state[1]) { fan_edge_counter[1] ++; fan_state[1] = READ(TACH_1); } } + diff --git a/Firmware/stepper.h b/Firmware/stepper.h index e46189cad..14192b91b 100644 --- a/Firmware/stepper.h +++ b/Firmware/stepper.h @@ -93,7 +93,7 @@ static void check_fans(); #ifdef HAVE_TMC2130_DRIVERS void tmc2130_check_overtemp(); -void tmc2130_write(uint8_t chipselect, uint8_t address,uint8_t wval1,uint8_t wval2,uint8_t wval3,uint8_t wval4); +void tmc2130_write(uint8_t chipselect, uint8_t address, uint8_t wval1, uint8_t wval2, uint8_t wval3, uint8_t wval4); uint8_t tmc2130_read8(uint8_t chipselect, uint8_t address); uint16_t tmc2130_readSG(uint8_t chipselect); uint16_t tmc2130_readTStep(uint8_t chipselect); @@ -105,6 +105,7 @@ uint8_t st_didLastHomingStall(); #endif + #ifdef BABYSTEPPING void babystep(const uint8_t axis,const bool direction); // perform a short step with a single stepper motor, outside of any convention #endif diff --git a/Firmware/temperature.cpp b/Firmware/temperature.cpp index c5be1b4fc..b91f53131 100644 --- a/Firmware/temperature.cpp +++ b/Firmware/temperature.cpp @@ -1,401 +1,415 @@ -/* - temperature.c - temperature control - Part of Marlin - - Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -/* - This firmware is a mashup between Sprinter and grbl. - (https://github.com/kliment/Sprinter) - (https://github.com/simen/grbl/tree) - - It has preliminary support for Matthew Roberts advance algorithm - http://reprap.org/pipermail/reprap-dev/2011-May/003323.html - - */ - - -#include "Marlin.h" -#include "ultralcd.h" -#include "temperature.h" -#include "watchdog.h" -#include "cardreader.h" - -#include "Sd2PinMap.h" - - -//=========================================================================== -//=============================public variables============================ -//=========================================================================== -int target_temperature[EXTRUDERS] = { 0 }; -int target_temperature_bed = 0; -int current_temperature_raw[EXTRUDERS] = { 0 }; -float current_temperature[EXTRUDERS] = { 0.0 }; -int current_temperature_bed_raw = 0; -float current_temperature_bed = 0.0; -#ifdef TEMP_SENSOR_1_AS_REDUNDANT - int redundant_temperature_raw = 0; - float redundant_temperature = 0.0; -#endif -#ifdef PIDTEMP - float Kp=DEFAULT_Kp; - float Ki=(DEFAULT_Ki*PID_dT); - float Kd=(DEFAULT_Kd/PID_dT); - #ifdef PID_ADD_EXTRUSION_RATE - float Kc=DEFAULT_Kc; - #endif -#endif //PIDTEMP - -#ifdef PIDTEMPBED - float bedKp=DEFAULT_bedKp; - float bedKi=(DEFAULT_bedKi*PID_dT); - float bedKd=(DEFAULT_bedKd/PID_dT); -#endif //PIDTEMPBED - -#ifdef FAN_SOFT_PWM - unsigned char fanSpeedSoftPwm; -#endif - -unsigned char soft_pwm_bed; - -#ifdef BABYSTEPPING - volatile int babystepsTodo[3]={0,0,0}; -#endif - -#ifdef FILAMENT_SENSOR - int current_raw_filwidth = 0; //Holds measured filament diameter - one extruder only -#endif -//=========================================================================== -//=============================private variables============================ -//=========================================================================== -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 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 pid_input[EXTRUDERS]; - // static float pid_output[EXTRUDERS]; - static bool pid_reset[EXTRUDERS]; -#endif //PIDTEMP -#ifdef PIDTEMPBED - //static cannot be external: - static float temp_iState_bed = { 0 }; - static float temp_dState_bed = { 0 }; - static float pTerm_bed; - static float iTerm_bed; - static float dTerm_bed; - //int output; - static float pid_error_bed; - static float temp_iState_min_bed; - static float temp_iState_max_bed; -#else //PIDTEMPBED - static unsigned long previous_millis_bed_heater; -#endif //PIDTEMPBED - static unsigned char soft_pwm[EXTRUDERS]; - -#ifdef FAN_SOFT_PWM - static unsigned char soft_pwm_fan; -#endif -#if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \ - (defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1) || \ - (defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1) - static unsigned long extruder_autofan_last_check; -#endif - -#if EXTRUDERS > 3 - # error Unsupported number of extruders -#elif EXTRUDERS > 2 - # define ARRAY_BY_EXTRUDERS(v1, v2, v3) { v1, v2, v3 } -#elif EXTRUDERS > 1 - # define ARRAY_BY_EXTRUDERS(v1, v2, v3) { v1, v2 } -#else - # define ARRAY_BY_EXTRUDERS(v1, v2, v3) { v1 } -#endif - -// 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 ); -static int minttemp[EXTRUDERS] = ARRAY_BY_EXTRUDERS( 0, 0, 0 ); -static int maxttemp[EXTRUDERS] = ARRAY_BY_EXTRUDERS( 16383, 16383, 16383 ); -#ifdef BED_MINTEMP -static int bed_minttemp_raw = HEATER_BED_RAW_LO_TEMP; -#endif -#ifdef BED_MAXTEMP -static int bed_maxttemp_raw = HEATER_BED_RAW_HI_TEMP; -#endif - -#ifdef TEMP_SENSOR_1_AS_REDUNDANT - static void *heater_ttbl_map[2] = {(void *)HEATER_0_TEMPTABLE, (void *)HEATER_1_TEMPTABLE }; - static uint8_t heater_ttbllen_map[2] = { HEATER_0_TEMPTABLE_LEN, HEATER_1_TEMPTABLE_LEN }; -#else - static void *heater_ttbl_map[EXTRUDERS] = ARRAY_BY_EXTRUDERS( (void *)HEATER_0_TEMPTABLE, (void *)HEATER_1_TEMPTABLE, (void *)HEATER_2_TEMPTABLE ); - static uint8_t heater_ttbllen_map[EXTRUDERS] = ARRAY_BY_EXTRUDERS( HEATER_0_TEMPTABLE_LEN, HEATER_1_TEMPTABLE_LEN, HEATER_2_TEMPTABLE_LEN ); -#endif - -static float analog2temp(int raw, uint8_t e); -static float analog2tempBed(int raw); -static void updateTemperaturesFromRawValues(); - -enum TempRunawayStates -{ - TempRunaway_INACTIVE = 0, - TempRunaway_PREHEAT = 1, - TempRunaway_ACTIVE = 2, -}; - -#ifdef WATCH_TEMP_PERIOD -int watch_start_temp[EXTRUDERS] = ARRAY_BY_EXTRUDERS(0,0,0); -unsigned long watchmillis[EXTRUDERS] = ARRAY_BY_EXTRUDERS(0,0,0); -#endif //WATCH_TEMP_PERIOD - -#ifndef SOFT_PWM_SCALE -#define SOFT_PWM_SCALE 0 -#endif - -#ifdef FILAMENT_SENSOR - static int meas_shift_index; //used to point to a delayed sample in buffer for filament width sensor -#endif -//=========================================================================== -//============================= functions ============================ -//=========================================================================== - -void PID_autotune(float temp, int extruder, int ncycles) -{ - float input = 0.0; - int cycles=0; - bool heating = true; - - unsigned long temp_millis = millis(); - unsigned long t1=temp_millis; - unsigned long t2=temp_millis; - long t_high = 0; - long t_low = 0; - - long bias, d; - float Ku, Tu; - float Kp, Ki, Kd; - float max = 0, min = 10000; - -#if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \ - (defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1) || \ - (defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1) - unsigned long extruder_autofan_last_check = millis(); -#endif - - if ((extruder >= EXTRUDERS) - #if (TEMP_BED_PIN <= -1) - ||(extruder < 0) - #endif - ){ - SERIAL_ECHOLN("PID Autotune failed. Bad extruder number."); - return; - } - - SERIAL_ECHOLN("PID Autotune start"); - - disable_heater(); // switch off all heaters. - - if (extruder<0) - { - soft_pwm_bed = (MAX_BED_POWER)/2; - bias = d = (MAX_BED_POWER)/2; - } - else - { - soft_pwm[extruder] = (PID_MAX)/2; - bias = d = (PID_MAX)/2; - } - - - - - for(;;) { - - if(temp_meas_ready == true) { // temp sample ready - updateTemperaturesFromRawValues(); - - input = (extruder<0)?current_temperature_bed:current_temperature[extruder]; - - max=max(max,input); - min=min(min,input); - - #if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \ - (defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1) || \ - (defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1) - if(millis() - extruder_autofan_last_check > 2500) { - checkExtruderAutoFans(); - extruder_autofan_last_check = millis(); - } - #endif - - if(heating == true && input > temp) { - if(millis() - t2 > 5000) { - heating=false; - if (extruder<0) - soft_pwm_bed = (bias - d) >> 1; - else - soft_pwm[extruder] = (bias - d) >> 1; - t1=millis(); - t_high=t1 - t2; - max=temp; - } - } - if(heating == false && input < temp) { - if(millis() - t1 > 5000) { - heating=true; - t2=millis(); - t_low=t2 - t1; - if(cycles > 0) { - bias += (d*(t_high - t_low))/(t_low + t_high); - bias = constrain(bias, 20 ,(extruder<0?(MAX_BED_POWER):(PID_MAX))-20); - if(bias > (extruder<0?(MAX_BED_POWER):(PID_MAX))/2) d = (extruder<0?(MAX_BED_POWER):(PID_MAX)) - 1 - bias; - else d = bias; - - SERIAL_PROTOCOLPGM(" bias: "); SERIAL_PROTOCOL(bias); - SERIAL_PROTOCOLPGM(" d: "); SERIAL_PROTOCOL(d); - SERIAL_PROTOCOLPGM(" min: "); SERIAL_PROTOCOL(min); - SERIAL_PROTOCOLPGM(" max: "); SERIAL_PROTOCOLLN(max); - if(cycles > 2) { - Ku = (4.0*d)/(3.14159*(max-min)/2.0); - Tu = ((float)(t_low + t_high)/1000.0); - SERIAL_PROTOCOLPGM(" Ku: "); SERIAL_PROTOCOL(Ku); - SERIAL_PROTOCOLPGM(" Tu: "); SERIAL_PROTOCOLLN(Tu); - Kp = 0.6*Ku; - Ki = 2*Kp/Tu; - Kd = Kp*Tu/8; - SERIAL_PROTOCOLLNPGM(" Classic PID "); - SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(Kp); - SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(Ki); - SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(Kd); - /* - Kp = 0.33*Ku; - Ki = Kp/Tu; - Kd = Kp*Tu/3; - SERIAL_PROTOCOLLNPGM(" Some overshoot "); - SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(Kp); - SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(Ki); - SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(Kd); - Kp = 0.2*Ku; - Ki = 2*Kp/Tu; - Kd = Kp*Tu/3; - SERIAL_PROTOCOLLNPGM(" No overshoot "); - SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(Kp); - SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(Ki); - SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(Kd); - */ - } - } - if (extruder<0) - soft_pwm_bed = (bias + d) >> 1; - else - soft_pwm[extruder] = (bias + d) >> 1; - cycles++; - min=temp; - } - } - } - if(input > (temp + 20)) { - SERIAL_PROTOCOLLNPGM("PID Autotune failed! Temperature too high"); - return; - } - if(millis() - temp_millis > 2000) { - int p; - if (extruder<0){ - p=soft_pwm_bed; - SERIAL_PROTOCOLPGM("ok B:"); - }else{ - p=soft_pwm[extruder]; - SERIAL_PROTOCOLPGM("ok T:"); - } - - SERIAL_PROTOCOL(input); - SERIAL_PROTOCOLPGM(" @:"); - SERIAL_PROTOCOLLN(p); - - temp_millis = millis(); - } - if(((millis() - t1) + (millis() - t2)) > (10L*60L*1000L*2L)) { - SERIAL_PROTOCOLLNPGM("PID Autotune failed! timeout"); - return; - } - if(cycles > ncycles) { - SERIAL_PROTOCOLLNPGM("PID Autotune finished! Put the last Kp, Ki and Kd constants from above into Configuration.h"); - return; - } - lcd_update(); - } -} - -void updatePID() -{ -#ifdef PIDTEMP - for(int e = 0; e < EXTRUDERS; e++) { - temp_iState_max[e] = PID_INTEGRAL_DRIVE_MAX / Ki; - } -#endif -#ifdef PIDTEMPBED - temp_iState_max_bed = PID_INTEGRAL_DRIVE_MAX / bedKi; -#endif -} - -int getHeaterPower(int heater) { - if (heater<0) - return soft_pwm_bed; - return soft_pwm[heater]; -} - -#if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \ - (defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1) || \ - (defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1) - - #if defined(FAN_PIN) && FAN_PIN > -1 - #if EXTRUDER_0_AUTO_FAN_PIN == FAN_PIN - #error "You cannot set EXTRUDER_0_AUTO_FAN_PIN equal to FAN_PIN" - #endif - #if EXTRUDER_1_AUTO_FAN_PIN == FAN_PIN - #error "You cannot set EXTRUDER_1_AUTO_FAN_PIN equal to FAN_PIN" - #endif - #if EXTRUDER_2_AUTO_FAN_PIN == FAN_PIN - #error "You cannot set EXTRUDER_2_AUTO_FAN_PIN equal to FAN_PIN" - #endif - #endif - -void setExtruderAutoFanState(int pin, bool state) -{ - unsigned char newFanSpeed = (state != 0) ? EXTRUDER_AUTO_FAN_SPEED : 0; - // this idiom allows both digital and PWM fan outputs (see M42 handling). - pinMode(pin, OUTPUT); - digitalWrite(pin, newFanSpeed); - analogWrite(pin, newFanSpeed); -} - +/* + temperature.c - temperature control + Part of Marlin + + Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +/* + This firmware is a mashup between Sprinter and grbl. + (https://github.com/kliment/Sprinter) + (https://github.com/simen/grbl/tree) + + It has preliminary support for Matthew Roberts advance algorithm + http://reprap.org/pipermail/reprap-dev/2011-May/003323.html + + */ + + +#include "Marlin.h" +#include "ultralcd.h" +#include "temperature.h" +#include "watchdog.h" +#include "cardreader.h" + +#include "Sd2PinMap.h" + + +//=========================================================================== +//=============================public variables============================ +//=========================================================================== +int target_temperature[EXTRUDERS] = { 0 }; +int target_temperature_bed = 0; +int current_temperature_raw[EXTRUDERS] = { 0 }; +float current_temperature[EXTRUDERS] = { 0.0 }; +int current_temperature_bed_raw = 0; +float current_temperature_bed = 0.0; +#ifdef TEMP_SENSOR_1_AS_REDUNDANT + int redundant_temperature_raw = 0; + float redundant_temperature = 0.0; +#endif + + +#ifdef PIDTEMP + float _Kp, _Ki, _Kd; + int pid_cycle, pid_number_of_cycles; + bool pid_tuning_finished = false; + float Kp=DEFAULT_Kp; + float Ki=(DEFAULT_Ki*PID_dT); + float Kd=(DEFAULT_Kd/PID_dT); + #ifdef PID_ADD_EXTRUSION_RATE + float Kc=DEFAULT_Kc; + #endif +#endif //PIDTEMP + +#ifdef PIDTEMPBED + float bedKp=DEFAULT_bedKp; + float bedKi=(DEFAULT_bedKi*PID_dT); + float bedKd=(DEFAULT_bedKd/PID_dT); +#endif //PIDTEMPBED + +#ifdef FAN_SOFT_PWM + unsigned char fanSpeedSoftPwm; +#endif + +unsigned char soft_pwm_bed; + +#ifdef BABYSTEPPING + volatile int babystepsTodo[3]={0,0,0}; +#endif + +#ifdef FILAMENT_SENSOR + int current_raw_filwidth = 0; //Holds measured filament diameter - one extruder only +#endif +//=========================================================================== +//=============================private variables============================ +//=========================================================================== +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 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 pid_input[EXTRUDERS]; + // static float pid_output[EXTRUDERS]; + static bool pid_reset[EXTRUDERS]; +#endif //PIDTEMP +#ifdef PIDTEMPBED + //static cannot be external: + static float temp_iState_bed = { 0 }; + static float temp_dState_bed = { 0 }; + static float pTerm_bed; + static float iTerm_bed; + static float dTerm_bed; + //int output; + static float pid_error_bed; + static float temp_iState_min_bed; + static float temp_iState_max_bed; +#else //PIDTEMPBED + static unsigned long previous_millis_bed_heater; +#endif //PIDTEMPBED + static unsigned char soft_pwm[EXTRUDERS]; + +#ifdef FAN_SOFT_PWM + static unsigned char soft_pwm_fan; +#endif +#if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \ + (defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1) || \ + (defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1) + static unsigned long extruder_autofan_last_check; +#endif + +#if EXTRUDERS > 3 + # error Unsupported number of extruders +#elif EXTRUDERS > 2 + # define ARRAY_BY_EXTRUDERS(v1, v2, v3) { v1, v2, v3 } +#elif EXTRUDERS > 1 + # define ARRAY_BY_EXTRUDERS(v1, v2, v3) { v1, v2 } +#else + # define ARRAY_BY_EXTRUDERS(v1, v2, v3) { v1 } +#endif + +// 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 ); +static int minttemp[EXTRUDERS] = ARRAY_BY_EXTRUDERS( 0, 0, 0 ); +static int maxttemp[EXTRUDERS] = ARRAY_BY_EXTRUDERS( 16383, 16383, 16383 ); +#ifdef BED_MINTEMP +static int bed_minttemp_raw = HEATER_BED_RAW_LO_TEMP; +#endif +#ifdef BED_MAXTEMP +static int bed_maxttemp_raw = HEATER_BED_RAW_HI_TEMP; +#endif + +#ifdef TEMP_SENSOR_1_AS_REDUNDANT + static void *heater_ttbl_map[2] = {(void *)HEATER_0_TEMPTABLE, (void *)HEATER_1_TEMPTABLE }; + static uint8_t heater_ttbllen_map[2] = { HEATER_0_TEMPTABLE_LEN, HEATER_1_TEMPTABLE_LEN }; +#else + static void *heater_ttbl_map[EXTRUDERS] = ARRAY_BY_EXTRUDERS( (void *)HEATER_0_TEMPTABLE, (void *)HEATER_1_TEMPTABLE, (void *)HEATER_2_TEMPTABLE ); + static uint8_t heater_ttbllen_map[EXTRUDERS] = ARRAY_BY_EXTRUDERS( HEATER_0_TEMPTABLE_LEN, HEATER_1_TEMPTABLE_LEN, HEATER_2_TEMPTABLE_LEN ); +#endif + +static float analog2temp(int raw, uint8_t e); +static float analog2tempBed(int raw); +static void updateTemperaturesFromRawValues(); + +enum TempRunawayStates +{ + TempRunaway_INACTIVE = 0, + TempRunaway_PREHEAT = 1, + TempRunaway_ACTIVE = 2, +}; + +#ifdef WATCH_TEMP_PERIOD +int watch_start_temp[EXTRUDERS] = ARRAY_BY_EXTRUDERS(0,0,0); +unsigned long watchmillis[EXTRUDERS] = ARRAY_BY_EXTRUDERS(0,0,0); +#endif //WATCH_TEMP_PERIOD + +#ifndef SOFT_PWM_SCALE +#define SOFT_PWM_SCALE 0 +#endif + +#ifdef FILAMENT_SENSOR + static int meas_shift_index; //used to point to a delayed sample in buffer for filament width sensor +#endif +//=========================================================================== +//============================= functions ============================ +//=========================================================================== + + void PID_autotune(float temp, int extruder, int ncycles) + { + pid_number_of_cycles = ncycles; + pid_tuning_finished = false; + float input = 0.0; + pid_cycle=0; + bool heating = true; + + unsigned long temp_millis = millis(); + unsigned long t1=temp_millis; + unsigned long t2=temp_millis; + long t_high = 0; + long t_low = 0; + + long bias, d; + float Ku, Tu; + float max = 0, min = 10000; + +#if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \ + (defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1) || \ + (defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1) + unsigned long extruder_autofan_last_check = millis(); +#endif + + if ((extruder >= EXTRUDERS) + #if (TEMP_BED_PIN <= -1) + ||(extruder < 0) + #endif + ){ + SERIAL_ECHOLN("PID Autotune failed. Bad extruder number."); + pid_tuning_finished = true; + pid_cycle = 0; + return; + } + + SERIAL_ECHOLN("PID Autotune start"); + + disable_heater(); // switch off all heaters. + + if (extruder<0) + { + soft_pwm_bed = (MAX_BED_POWER)/2; + bias = d = (MAX_BED_POWER)/2; + } + else + { + soft_pwm[extruder] = (PID_MAX)/2; + bias = d = (PID_MAX)/2; + } + + + + + for(;;) { + + if(temp_meas_ready == true) { // temp sample ready + updateTemperaturesFromRawValues(); + + input = (extruder<0)?current_temperature_bed:current_temperature[extruder]; + + max=max(max,input); + min=min(min,input); + + #if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \ + (defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1) || \ + (defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1) + if(millis() - extruder_autofan_last_check > 2500) { + checkExtruderAutoFans(); + extruder_autofan_last_check = millis(); + } + #endif + + if(heating == true && input > temp) { + if(millis() - t2 > 5000) { + heating=false; + if (extruder<0) + soft_pwm_bed = (bias - d) >> 1; + else + soft_pwm[extruder] = (bias - d) >> 1; + t1=millis(); + t_high=t1 - t2; + max=temp; + } + } + if(heating == false && input < temp) { + if(millis() - t1 > 5000) { + heating=true; + t2=millis(); + t_low=t2 - t1; + if(pid_cycle > 0) { + bias += (d*(t_high - t_low))/(t_low + t_high); + bias = constrain(bias, 20 ,(extruder<0?(MAX_BED_POWER):(PID_MAX))-20); + if(bias > (extruder<0?(MAX_BED_POWER):(PID_MAX))/2) d = (extruder<0?(MAX_BED_POWER):(PID_MAX)) - 1 - bias; + else d = bias; + + SERIAL_PROTOCOLPGM(" bias: "); SERIAL_PROTOCOL(bias); + SERIAL_PROTOCOLPGM(" d: "); SERIAL_PROTOCOL(d); + SERIAL_PROTOCOLPGM(" min: "); SERIAL_PROTOCOL(min); + SERIAL_PROTOCOLPGM(" max: "); SERIAL_PROTOCOLLN(max); + if(pid_cycle > 2) { + Ku = (4.0*d)/(3.14159*(max-min)/2.0); + Tu = ((float)(t_low + t_high)/1000.0); + SERIAL_PROTOCOLPGM(" Ku: "); SERIAL_PROTOCOL(Ku); + SERIAL_PROTOCOLPGM(" Tu: "); SERIAL_PROTOCOLLN(Tu); + _Kp = 0.6*Ku; + _Ki = 2*_Kp/Tu; + _Kd = _Kp*Tu/8; + SERIAL_PROTOCOLLNPGM(" Classic PID "); + SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(_Kp); + SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(_Ki); + SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(_Kd); + /* + _Kp = 0.33*Ku; + _Ki = _Kp/Tu; + _Kd = _Kp*Tu/3; + SERIAL_PROTOCOLLNPGM(" Some overshoot "); + SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(_Kp); + SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(_Ki); + SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(_Kd); + _Kp = 0.2*Ku; + _Ki = 2*_Kp/Tu; + _Kd = _Kp*Tu/3; + SERIAL_PROTOCOLLNPGM(" No overshoot "); + SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(_Kp); + SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(_Ki); + SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(_Kd); + */ + } + } + if (extruder<0) + soft_pwm_bed = (bias + d) >> 1; + else + soft_pwm[extruder] = (bias + d) >> 1; + pid_cycle++; + min=temp; + } + } + } + if(input > (temp + 20)) { + SERIAL_PROTOCOLLNPGM("PID Autotune failed! Temperature too high"); + pid_tuning_finished = true; + pid_cycle = 0; + return; + } + if(millis() - temp_millis > 2000) { + int p; + if (extruder<0){ + p=soft_pwm_bed; + SERIAL_PROTOCOLPGM("ok B:"); + }else{ + p=soft_pwm[extruder]; + SERIAL_PROTOCOLPGM("ok T:"); + } + + SERIAL_PROTOCOL(input); + SERIAL_PROTOCOLPGM(" @:"); + SERIAL_PROTOCOLLN(p); + + temp_millis = millis(); + } + if(((millis() - t1) + (millis() - t2)) > (10L*60L*1000L*2L)) { + SERIAL_PROTOCOLLNPGM("PID Autotune failed! timeout"); + pid_tuning_finished = true; + pid_cycle = 0; + return; + } + if(pid_cycle > ncycles) { + SERIAL_PROTOCOLLNPGM("PID Autotune finished! Put the last Kp, Ki and Kd constants from above into Configuration.h"); + pid_tuning_finished = true; + pid_cycle = 0; + return; + } + lcd_update(); + } +} + +void updatePID() +{ +#ifdef PIDTEMP + for(int e = 0; e < EXTRUDERS; e++) { + temp_iState_max[e] = PID_INTEGRAL_DRIVE_MAX / Ki; + } +#endif +#ifdef PIDTEMPBED + temp_iState_max_bed = PID_INTEGRAL_DRIVE_MAX / bedKi; +#endif +} + +int getHeaterPower(int heater) { + if (heater<0) + return soft_pwm_bed; + return soft_pwm[heater]; +} + +#if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \ + (defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1) || \ + (defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1) + + #if defined(FAN_PIN) && FAN_PIN > -1 + #if EXTRUDER_0_AUTO_FAN_PIN == FAN_PIN + #error "You cannot set EXTRUDER_0_AUTO_FAN_PIN equal to FAN_PIN" + #endif + #if EXTRUDER_1_AUTO_FAN_PIN == FAN_PIN + #error "You cannot set EXTRUDER_1_AUTO_FAN_PIN equal to FAN_PIN" + #endif + #if EXTRUDER_2_AUTO_FAN_PIN == FAN_PIN + #error "You cannot set EXTRUDER_2_AUTO_FAN_PIN equal to FAN_PIN" + #endif + #endif + +void setExtruderAutoFanState(int pin, bool state) +{ + unsigned char newFanSpeed = (state != 0) ? EXTRUDER_AUTO_FAN_SPEED : 0; + // this idiom allows both digital and PWM fan outputs (see M42 handling). + pinMode(pin, OUTPUT); + digitalWrite(pin, newFanSpeed); + analogWrite(pin, newFanSpeed); +} + void countFanSpeed() { - fan_speed[0] = (fan_edge_counter[0] * (float(250) / (millis() - extruder_autofan_last_check))); - fan_speed[1] = (fan_edge_counter[1] * (float(250) / (millis() - extruder_autofan_last_check))); - + fan_speed[0] = (fan_edge_counter[0] * (float(250) / (millis() - extruder_autofan_last_check))); + fan_speed[1] = (fan_edge_counter[1] * (float(250) / (millis() - extruder_autofan_last_check))); + fan_edge_counter[0] = 0; fan_edge_counter[1] = 0; } @@ -427,7 +441,7 @@ void fanSpeedError(unsigned char _fan) { WRITE(BEEPER, LOW); delayMicroseconds(100);*/ - + SERIAL_ERROR_START; switch (_fan) { case 0: @@ -440,1576 +454,1586 @@ void fanSpeedError(unsigned char _fan) { break; } } - -void checkExtruderAutoFans() -{ - uint8_t fanState = 0; - - // which fan pins need to be turned on? - #if defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1 - if (current_temperature[0] > EXTRUDER_AUTO_FAN_TEMPERATURE) - fanState |= 1; - #endif - #if defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1 - if (current_temperature[1] > EXTRUDER_AUTO_FAN_TEMPERATURE) - { - if (EXTRUDER_1_AUTO_FAN_PIN == EXTRUDER_0_AUTO_FAN_PIN) - fanState |= 1; - else - fanState |= 2; - } - #endif - #if defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1 - if (current_temperature[2] > EXTRUDER_AUTO_FAN_TEMPERATURE) - { - if (EXTRUDER_2_AUTO_FAN_PIN == EXTRUDER_0_AUTO_FAN_PIN) - fanState |= 1; - else if (EXTRUDER_2_AUTO_FAN_PIN == EXTRUDER_1_AUTO_FAN_PIN) - fanState |= 2; - else - fanState |= 4; - } - #endif - - // update extruder auto fan states - #if defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1 - setExtruderAutoFanState(EXTRUDER_0_AUTO_FAN_PIN, (fanState & 1) != 0); - #endif - #if defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1 - if (EXTRUDER_1_AUTO_FAN_PIN != EXTRUDER_0_AUTO_FAN_PIN) - setExtruderAutoFanState(EXTRUDER_1_AUTO_FAN_PIN, (fanState & 2) != 0); - #endif - #if defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1 - if (EXTRUDER_2_AUTO_FAN_PIN != EXTRUDER_0_AUTO_FAN_PIN - && EXTRUDER_2_AUTO_FAN_PIN != EXTRUDER_1_AUTO_FAN_PIN) - setExtruderAutoFanState(EXTRUDER_2_AUTO_FAN_PIN, (fanState & 4) != 0); - #endif -} - -#endif // any extruder auto fan pins set - -void manage_heater() -{ - float pid_input; - float pid_output; - - if(temp_meas_ready != true) //better readability - return; - - updateTemperaturesFromRawValues(); - -#ifdef TEMP_RUNAWAY_BED_HYSTERESIS - temp_runaway_check(0, target_temperature_bed, current_temperature_bed, (int)soft_pwm_bed, true); -#endif - - for(int e = 0; e < EXTRUDERS; e++) - { - -#ifdef TEMP_RUNAWAY_EXTRUDER_HYSTERESIS - temp_runaway_check(e+1, target_temperature[e], current_temperature[e], (int)soft_pwm[e], false); -#endif - - #ifdef PIDTEMP - 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) { - pid_output = 0; - pid_reset[e] = true; - } - else { - if(pid_reset[e] == true) { - temp_iState[e] = 0.0; - pid_reset[e] = false; - } - pTerm[e] = 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] = Ki * temp_iState[e]; - - //K1 defined in Configuration.h in the PID settings - #define K2 (1.0-K1) - dTerm[e] = (Kd * (pid_input - temp_dState[e]))*K2 + (K1 * dTerm[e]); - pid_output = pTerm[e] + iTerm[e] - dTerm[e]; - if (pid_output > PID_MAX) { - if (pid_error[e] > 0 ) temp_iState[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 - pid_output=0; - } - } - temp_dState[e] = pid_input; - #else - pid_output = constrain(target_temperature[e], 0, PID_MAX); - #endif //PID_OPENLOOP - #ifdef PID_DEBUG - SERIAL_ECHO_START; - SERIAL_ECHO(" PID_DEBUG "); - SERIAL_ECHO(e); - SERIAL_ECHO(": Input "); - SERIAL_ECHO(pid_input); - SERIAL_ECHO(" Output "); - SERIAL_ECHO(pid_output); - SERIAL_ECHO(" pTerm "); - SERIAL_ECHO(pTerm[e]); - SERIAL_ECHO(" iTerm "); - SERIAL_ECHO(iTerm[e]); - SERIAL_ECHO(" dTerm "); - SERIAL_ECHOLN(dTerm[e]); - #endif //PID_DEBUG - #else /* PID off */ - pid_output = 0; - if(current_temperature[e] < target_temperature[e]) { - pid_output = PID_MAX; - } - #endif - - // Check if temperature is within the correct range - if((current_temperature[e] > minttemp[e]) && (current_temperature[e] < maxttemp[e])) - { - soft_pwm[e] = (int)pid_output >> 1; - } - else { - soft_pwm[e] = 0; - } - - #ifdef WATCH_TEMP_PERIOD - if(watchmillis[e] && millis() - watchmillis[e] > WATCH_TEMP_PERIOD) - { - if(degHotend(e) < watch_start_temp[e] + WATCH_TEMP_INCREASE) - { - setTargetHotend(0, e); - LCD_MESSAGEPGM("Heating failed"); - SERIAL_ECHO_START; - SERIAL_ECHOLN("Heating failed"); - }else{ - watchmillis[e] = 0; - } - } - #endif - #ifdef TEMP_SENSOR_1_AS_REDUNDANT - if(fabs(current_temperature[0] - redundant_temperature) > MAX_REDUNDANT_TEMP_SENSOR_DIFF) { - disable_heater(); - if(IsStopped() == false) { - SERIAL_ERROR_START; - SERIAL_ERRORLNPGM("Extruder switched off. Temperature difference between temp sensors is too high !"); - LCD_ALERTMESSAGEPGM("Err: REDUNDANT TEMP ERROR"); - } - #ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE - Stop(); - #endif - } - #endif - } // End extruder for loop - - #if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \ - (defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1) || \ - (defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1) - if(millis() - extruder_autofan_last_check > 1000) // only need to check fan state very infrequently - { + + +void checkExtruderAutoFans() +{ + uint8_t fanState = 0; + + // which fan pins need to be turned on? + #if defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1 + if (current_temperature[0] > EXTRUDER_AUTO_FAN_TEMPERATURE) + fanState |= 1; + #endif + #if defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1 + if (current_temperature[1] > EXTRUDER_AUTO_FAN_TEMPERATURE) + { + if (EXTRUDER_1_AUTO_FAN_PIN == EXTRUDER_0_AUTO_FAN_PIN) + fanState |= 1; + else + fanState |= 2; + } + #endif + #if defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1 + if (current_temperature[2] > EXTRUDER_AUTO_FAN_TEMPERATURE) + { + if (EXTRUDER_2_AUTO_FAN_PIN == EXTRUDER_0_AUTO_FAN_PIN) + fanState |= 1; + else if (EXTRUDER_2_AUTO_FAN_PIN == EXTRUDER_1_AUTO_FAN_PIN) + fanState |= 2; + else + fanState |= 4; + } + #endif + + // update extruder auto fan states + #if defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1 + setExtruderAutoFanState(EXTRUDER_0_AUTO_FAN_PIN, (fanState & 1) != 0); + #endif + #if defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1 + if (EXTRUDER_1_AUTO_FAN_PIN != EXTRUDER_0_AUTO_FAN_PIN) + setExtruderAutoFanState(EXTRUDER_1_AUTO_FAN_PIN, (fanState & 2) != 0); + #endif + #if defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1 + if (EXTRUDER_2_AUTO_FAN_PIN != EXTRUDER_0_AUTO_FAN_PIN + && EXTRUDER_2_AUTO_FAN_PIN != EXTRUDER_1_AUTO_FAN_PIN) + setExtruderAutoFanState(EXTRUDER_2_AUTO_FAN_PIN, (fanState & 4) != 0); + #endif +} + +#endif // any extruder auto fan pins set + +void manage_heater() +{ + float pid_input; + float pid_output; + + if(temp_meas_ready != true) //better readability + return; + + updateTemperaturesFromRawValues(); + +#ifdef TEMP_RUNAWAY_BED_HYSTERESIS + temp_runaway_check(0, target_temperature_bed, current_temperature_bed, (int)soft_pwm_bed, true); +#endif + + for(int e = 0; e < EXTRUDERS; e++) + { + +#ifdef TEMP_RUNAWAY_EXTRUDER_HYSTERESIS + temp_runaway_check(e+1, target_temperature[e], current_temperature[e], (int)soft_pwm[e], false); +#endif + + #ifdef PIDTEMP + 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) { + pid_output = 0; + pid_reset[e] = true; + } + else { + if(pid_reset[e] == true) { + temp_iState[e] = 0.0; + pid_reset[e] = false; + } + pTerm[e] = 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] = Ki * temp_iState[e]; + + //K1 defined in Configuration.h in the PID settings + #define K2 (1.0-K1) + dTerm[e] = (Kd * (pid_input - temp_dState[e]))*K2 + (K1 * dTerm[e]); + pid_output = pTerm[e] + iTerm[e] - dTerm[e]; + if (pid_output > PID_MAX) { + if (pid_error[e] > 0 ) temp_iState[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 + pid_output=0; + } + } + temp_dState[e] = pid_input; + #else + pid_output = constrain(target_temperature[e], 0, PID_MAX); + #endif //PID_OPENLOOP + #ifdef PID_DEBUG + SERIAL_ECHO_START; + SERIAL_ECHO(" PID_DEBUG "); + SERIAL_ECHO(e); + SERIAL_ECHO(": Input "); + SERIAL_ECHO(pid_input); + SERIAL_ECHO(" Output "); + SERIAL_ECHO(pid_output); + SERIAL_ECHO(" pTerm "); + SERIAL_ECHO(pTerm[e]); + SERIAL_ECHO(" iTerm "); + SERIAL_ECHO(iTerm[e]); + SERIAL_ECHO(" dTerm "); + SERIAL_ECHOLN(dTerm[e]); + #endif //PID_DEBUG + #else /* PID off */ + pid_output = 0; + if(current_temperature[e] < target_temperature[e]) { + pid_output = PID_MAX; + } + #endif + + // Check if temperature is within the correct range + if((current_temperature[e] > minttemp[e]) && (current_temperature[e] < maxttemp[e])) + { + soft_pwm[e] = (int)pid_output >> 1; + } + else { + soft_pwm[e] = 0; + } + + #ifdef WATCH_TEMP_PERIOD + if(watchmillis[e] && millis() - watchmillis[e] > WATCH_TEMP_PERIOD) + { + if(degHotend(e) < watch_start_temp[e] + WATCH_TEMP_INCREASE) + { + setTargetHotend(0, e); + LCD_MESSAGEPGM("Heating failed"); + SERIAL_ECHO_START; + SERIAL_ECHOLN("Heating failed"); + }else{ + watchmillis[e] = 0; + } + } + #endif + #ifdef TEMP_SENSOR_1_AS_REDUNDANT + if(fabs(current_temperature[0] - redundant_temperature) > MAX_REDUNDANT_TEMP_SENSOR_DIFF) { + disable_heater(); + if(IsStopped() == false) { + SERIAL_ERROR_START; + SERIAL_ERRORLNPGM("Extruder switched off. Temperature difference between temp sensors is too high !"); + LCD_ALERTMESSAGEPGM("Err: REDUNDANT TEMP ERROR"); + } + #ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE + Stop(); + #endif + } + #endif + } // End extruder for loop + + #if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \ + (defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1) || \ + (defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1) + if(millis() - extruder_autofan_last_check > 1000) // only need to check fan state very infrequently + { countFanSpeed(); checkFanSpeed(); - checkExtruderAutoFans(); - extruder_autofan_last_check = millis(); - } - #endif - - #ifndef PIDTEMPBED - if(millis() - previous_millis_bed_heater < BED_CHECK_INTERVAL) - return; - previous_millis_bed_heater = millis(); - #endif - - #if TEMP_SENSOR_BED != 0 - - #ifdef PIDTEMPBED - pid_input = current_temperature_bed; - - #ifndef PID_OPENLOOP - pid_error_bed = target_temperature_bed - pid_input; - pTerm_bed = bedKp * pid_error_bed; - temp_iState_bed += pid_error_bed; - temp_iState_bed = constrain(temp_iState_bed, temp_iState_min_bed, temp_iState_max_bed); - iTerm_bed = bedKi * temp_iState_bed; - - //K1 defined in Configuration.h in the PID settings - #define K2 (1.0-K1) - dTerm_bed= (bedKd * (pid_input - temp_dState_bed))*K2 + (K1 * dTerm_bed); - temp_dState_bed = pid_input; - - pid_output = pTerm_bed + iTerm_bed - dTerm_bed; - if (pid_output > MAX_BED_POWER) { - if (pid_error_bed > 0 ) temp_iState_bed -= pid_error_bed; // conditional un-integration - pid_output=MAX_BED_POWER; - } else if (pid_output < 0){ - if (pid_error_bed < 0 ) temp_iState_bed -= pid_error_bed; // conditional un-integration - pid_output=0; - } - - #else - pid_output = constrain(target_temperature_bed, 0, MAX_BED_POWER); - #endif //PID_OPENLOOP - - if((current_temperature_bed > BED_MINTEMP) && (current_temperature_bed < BED_MAXTEMP)) - { - soft_pwm_bed = (int)pid_output >> 1; - } - else { - soft_pwm_bed = 0; - } - - #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 >= target_temperature_bed) - { - soft_pwm_bed = 0; - } - else - { - soft_pwm_bed = MAX_BED_POWER>>1; - } - } - else - { - soft_pwm_bed = 0; - 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 > target_temperature_bed + BED_HYSTERESIS) - { - soft_pwm_bed = 0; - } - else if(current_temperature_bed <= target_temperature_bed - BED_HYSTERESIS) - { - soft_pwm_bed = MAX_BED_POWER>>1; - } - } - else - { - soft_pwm_bed = 0; - WRITE(HEATER_BED_PIN,LOW); - } - #endif - #endif - -//code for controlling the extruder rate based on the width sensor -#ifdef FILAMENT_SENSOR - if(filament_sensor) - { - meas_shift_index=delay_index1-meas_delay_cm; - if(meas_shift_index<0) - meas_shift_index = meas_shift_index + (MAX_MEASUREMENT_DELAY+1); //loop around buffer if needed - - //get the delayed info and add 100 to reconstitute to a percent of the nominal filament diameter - //then square it to get an area - - if(meas_shift_index<0) - meas_shift_index=0; - else if (meas_shift_index>MAX_MEASUREMENT_DELAY) - meas_shift_index=MAX_MEASUREMENT_DELAY; - - volumetric_multiplier[FILAMENT_SENSOR_EXTRUDER_NUM] = pow((float)(100+measurement_delay[meas_shift_index])/100.0,2); - if (volumetric_multiplier[FILAMENT_SENSOR_EXTRUDER_NUM] <0.01) - volumetric_multiplier[FILAMENT_SENSOR_EXTRUDER_NUM]=0.01; - } -#endif -} - -#define PGM_RD_W(x) (short)pgm_read_word(&x) -// Derived from RepRap FiveD extruder::getTemperature() -// For hot end temperature measurement. -static float analog2temp(int raw, uint8_t e) { -#ifdef TEMP_SENSOR_1_AS_REDUNDANT - if(e > EXTRUDERS) -#else - if(e >= EXTRUDERS) -#endif - { - SERIAL_ERROR_START; - SERIAL_ERROR((int)e); - SERIAL_ERRORLNPGM(" - Invalid extruder number !"); - kill(); - return 0.0; - } - #ifdef HEATER_0_USES_MAX6675 - if (e == 0) - { - return 0.25 * raw; - } - #endif - - if(heater_ttbl_map[e] != NULL) - { - float celsius = 0; - uint8_t i; - short (*tt)[][2] = (short (*)[][2])(heater_ttbl_map[e]); - - for (i=1; i raw) - { - celsius = PGM_RD_W((*tt)[i-1][1]) + - (raw - PGM_RD_W((*tt)[i-1][0])) * - (float)(PGM_RD_W((*tt)[i][1]) - PGM_RD_W((*tt)[i-1][1])) / - (float)(PGM_RD_W((*tt)[i][0]) - PGM_RD_W((*tt)[i-1][0])); - break; - } - } - - // Overflow: Set to last value in the table - if (i == heater_ttbllen_map[e]) celsius = PGM_RD_W((*tt)[i-1][1]); - - return celsius; - } - return ((raw * ((5.0 * 100.0) / 1024.0) / OVERSAMPLENR) * TEMP_SENSOR_AD595_GAIN) + TEMP_SENSOR_AD595_OFFSET; -} - -// Derived from RepRap FiveD extruder::getTemperature() -// For bed temperature measurement. -static float analog2tempBed(int raw) { - #ifdef BED_USES_THERMISTOR - float celsius = 0; - byte i; - - for (i=1; i raw) - { - celsius = PGM_RD_W(BEDTEMPTABLE[i-1][1]) + - (raw - PGM_RD_W(BEDTEMPTABLE[i-1][0])) * - (float)(PGM_RD_W(BEDTEMPTABLE[i][1]) - PGM_RD_W(BEDTEMPTABLE[i-1][1])) / - (float)(PGM_RD_W(BEDTEMPTABLE[i][0]) - PGM_RD_W(BEDTEMPTABLE[i-1][0])); - break; - } - } - - // Overflow: Set to last value in the table - if (i == BEDTEMPTABLE_LEN) celsius = PGM_RD_W(BEDTEMPTABLE[i-1][1]); - - - // temperature offset adjustment -#ifdef BED_OFFSET - float _offset = BED_OFFSET; - float _offset_center = BED_OFFSET_CENTER; - float _offset_start = BED_OFFSET_START; - float _first_koef = (_offset / 2) / (_offset_center - _offset_start); - float _second_koef = (_offset / 2) / (100 - _offset_center); - - - if (celsius >= _offset_start && celsius <= _offset_center) - { - celsius = celsius + (_first_koef * (celsius - _offset_start)); - } - else if (celsius > _offset_center && celsius <= 100) - { - celsius = celsius + (_first_koef * (_offset_center - _offset_start)) + ( _second_koef * ( celsius - ( 100 - _offset_center ) )) ; - } - else if (celsius > 100) - { - celsius = celsius + _offset; - } -#endif - - - return celsius; - #elif defined BED_USES_AD595 - return ((raw * ((5.0 * 100.0) / 1024.0) / OVERSAMPLENR) * TEMP_SENSOR_AD595_GAIN) + TEMP_SENSOR_AD595_OFFSET; - #else - return 0; - #endif -} - -/* Called to get the raw values into the the actual temperatures. The raw values are created in interrupt context, - and this function is called from normal context as it is too slow to run in interrupts and will block the stepper routine otherwise */ -static void updateTemperaturesFromRawValues() -{ - for(uint8_t e=0;e -1) //check if a sensor is supported - filament_width_meas = analog2widthFil(); - #endif - //Reset the watchdog after we know we have a temperature measurement. - watchdog_reset(); - - CRITICAL_SECTION_START; - temp_meas_ready = false; - CRITICAL_SECTION_END; -} - - -// For converting raw Filament Width to milimeters -#ifdef FILAMENT_SENSOR -float analog2widthFil() { -return current_raw_filwidth/16383.0*5.0; -//return current_raw_filwidth; -} - -// For converting raw Filament Width to a ratio -int widthFil_to_size_ratio() { - -float temp; - -temp=filament_width_meas; -if(filament_width_measMEASURED_UPPER_LIMIT) - temp= MEASURED_UPPER_LIMIT; - - -return(filament_width_nominal/temp*100); - - -} -#endif - - - - - -void tp_init() -{ -#if MB(RUMBA) && ((TEMP_SENSOR_0==-1)||(TEMP_SENSOR_1==-1)||(TEMP_SENSOR_2==-1)||(TEMP_SENSOR_BED==-1)) - //disable RUMBA JTAG in case the thermocouple extension is plugged on top of JTAG connector - MCUCR=(1< -1) - SET_OUTPUT(HEATER_0_PIN); - #endif - #if defined(HEATER_1_PIN) && (HEATER_1_PIN > -1) - SET_OUTPUT(HEATER_1_PIN); - #endif - #if defined(HEATER_2_PIN) && (HEATER_2_PIN > -1) - SET_OUTPUT(HEATER_2_PIN); - #endif - #if defined(HEATER_BED_PIN) && (HEATER_BED_PIN > -1) - SET_OUTPUT(HEATER_BED_PIN); - #endif - #if defined(FAN_PIN) && (FAN_PIN > -1) - SET_OUTPUT(FAN_PIN); - #ifdef FAST_PWM_FAN - setPwmFrequency(FAN_PIN, 1); // No prescaling. Pwm frequency = F_CPU/256/8 - #endif - #ifdef FAN_SOFT_PWM - soft_pwm_fan = fanSpeedSoftPwm / 2; - #endif - #endif - - #ifdef HEATER_0_USES_MAX6675 - #ifndef SDSUPPORT - SET_OUTPUT(SCK_PIN); - WRITE(SCK_PIN,0); - - SET_OUTPUT(MOSI_PIN); - WRITE(MOSI_PIN,1); - - SET_INPUT(MISO_PIN); - WRITE(MISO_PIN,1); - #endif - /* Using pinMode and digitalWrite, as that was the only way I could get it to compile */ - - //Have to toggle SD card CS pin to low first, to enable firmware to talk with SD card - pinMode(SS_PIN, OUTPUT); - digitalWrite(SS_PIN,0); - pinMode(MAX6675_SS, OUTPUT); - digitalWrite(MAX6675_SS,1); - #endif - - // Set analog inputs - ADCSRA = 1< -1) - #if TEMP_0_PIN < 8 - DIDR0 |= 1 << TEMP_0_PIN; - #else - DIDR2 |= 1<<(TEMP_0_PIN - 8); - #endif - #endif - #if defined(TEMP_1_PIN) && (TEMP_1_PIN > -1) - #if TEMP_1_PIN < 8 - DIDR0 |= 1< -1) - #if TEMP_2_PIN < 8 - DIDR0 |= 1 << TEMP_2_PIN; - #else - DIDR2 |= 1<<(TEMP_2_PIN - 8); - #endif - #endif - #if defined(TEMP_BED_PIN) && (TEMP_BED_PIN > -1) - #if TEMP_BED_PIN < 8 - DIDR0 |= 1< -1) - #if FILWIDTH_PIN < 8 - DIDR0 |= 1< HEATER_0_MAXTEMP) { -#if HEATER_0_RAW_LO_TEMP < HEATER_0_RAW_HI_TEMP - maxttemp_raw[0] -= OVERSAMPLENR; -#else - maxttemp_raw[0] += OVERSAMPLENR; -#endif - } -#endif //MAXTEMP - -#if (EXTRUDERS > 1) && defined(HEATER_1_MINTEMP) - minttemp[1] = HEATER_1_MINTEMP; - while(analog2temp(minttemp_raw[1], 1) < HEATER_1_MINTEMP) { -#if HEATER_1_RAW_LO_TEMP < HEATER_1_RAW_HI_TEMP - minttemp_raw[1] += OVERSAMPLENR; -#else - minttemp_raw[1] -= OVERSAMPLENR; -#endif - } -#endif // MINTEMP 1 -#if (EXTRUDERS > 1) && defined(HEATER_1_MAXTEMP) - maxttemp[1] = HEATER_1_MAXTEMP; - while(analog2temp(maxttemp_raw[1], 1) > HEATER_1_MAXTEMP) { -#if HEATER_1_RAW_LO_TEMP < HEATER_1_RAW_HI_TEMP - maxttemp_raw[1] -= OVERSAMPLENR; -#else - maxttemp_raw[1] += OVERSAMPLENR; -#endif - } -#endif //MAXTEMP 1 - -#if (EXTRUDERS > 2) && defined(HEATER_2_MINTEMP) - minttemp[2] = HEATER_2_MINTEMP; - while(analog2temp(minttemp_raw[2], 2) < HEATER_2_MINTEMP) { -#if HEATER_2_RAW_LO_TEMP < HEATER_2_RAW_HI_TEMP - minttemp_raw[2] += OVERSAMPLENR; -#else - minttemp_raw[2] -= OVERSAMPLENR; -#endif - } -#endif //MINTEMP 2 -#if (EXTRUDERS > 2) && defined(HEATER_2_MAXTEMP) - maxttemp[2] = HEATER_2_MAXTEMP; - while(analog2temp(maxttemp_raw[2], 2) > HEATER_2_MAXTEMP) { -#if HEATER_2_RAW_LO_TEMP < HEATER_2_RAW_HI_TEMP - maxttemp_raw[2] -= OVERSAMPLENR; -#else - maxttemp_raw[2] += OVERSAMPLENR; -#endif - } -#endif //MAXTEMP 2 - -#ifdef BED_MINTEMP - /* No bed MINTEMP error implemented?!? */ - while(analog2tempBed(bed_minttemp_raw) < BED_MINTEMP) { -#if HEATER_BED_RAW_LO_TEMP < HEATER_BED_RAW_HI_TEMP - bed_minttemp_raw += OVERSAMPLENR; -#else - bed_minttemp_raw -= OVERSAMPLENR; -#endif - } - -#endif //BED_MINTEMP -#ifdef BED_MAXTEMP - while(analog2tempBed(bed_maxttemp_raw) > BED_MAXTEMP) { -#if HEATER_BED_RAW_LO_TEMP < HEATER_BED_RAW_HI_TEMP - bed_maxttemp_raw -= OVERSAMPLENR; -#else - bed_maxttemp_raw += OVERSAMPLENR; -#endif - } -#endif //BED_MAXTEMP -} - -void setWatch() -{ -#ifdef WATCH_TEMP_PERIOD - for (int e = 0; e < EXTRUDERS; e++) - { - if(degHotend(e) < degTargetHotend(e) - (WATCH_TEMP_INCREASE * 2)) - { - watch_start_temp[e] = degHotend(e); - watchmillis[e] = millis(); - } - } -#endif -} - -#if (defined (TEMP_RUNAWAY_BED_HYSTERESIS) && TEMP_RUNAWAY_BED_TIMEOUT > 0) || (defined (TEMP_RUNAWAY_EXTRUDER_HYSTERESIS) && TEMP_RUNAWAY_EXTRUDER_TIMEOUT > 0) -void temp_runaway_check(int _heater_id, float _target_temperature, float _current_temperature, float _output, bool _isbed) -{ - float __hysteresis = 0; - int __timeout = 0; - bool temp_runaway_check_active = false; - static float __preheat_start = 0; - static int __preheat_counter = 0; - static int __preheat_errors = 0; - - _heater_id = (_isbed) ? _heater_id++ : _heater_id; - -#ifdef TEMP_RUNAWAY_BED_TIMEOUT - if (_isbed) - { - __hysteresis = TEMP_RUNAWAY_BED_HYSTERESIS; - __timeout = TEMP_RUNAWAY_BED_TIMEOUT; - } -#endif -#ifdef TEMP_RUNAWAY_EXTRUDER_TIMEOUT - if (!_isbed) - { - __hysteresis = TEMP_RUNAWAY_EXTRUDER_HYSTERESIS; - __timeout = TEMP_RUNAWAY_EXTRUDER_TIMEOUT; - } -#endif - - if (millis() - temp_runaway_timer[_heater_id] > 2000) - { - - temp_runaway_timer[_heater_id] = millis(); - if (_output == 0) - { - temp_runaway_check_active = false; - temp_runaway_error_counter[_heater_id] = 0; - } - - if (temp_runaway_target[_heater_id] != _target_temperature) - { - if (_target_temperature > 0) - { - temp_runaway_status[_heater_id] = TempRunaway_PREHEAT; - temp_runaway_target[_heater_id] = _target_temperature; - __preheat_start = _current_temperature; - __preheat_counter = 0; - } - else - { - temp_runaway_status[_heater_id] = TempRunaway_INACTIVE; - temp_runaway_target[_heater_id] = _target_temperature; - } - } - - if (temp_runaway_status[_heater_id] == TempRunaway_PREHEAT) - { - if (_current_temperature < 150) - { - __preheat_counter++; - if (__preheat_counter > 8) - { - if (_current_temperature - __preheat_start < 2) { - __preheat_errors++; - } - else { - __preheat_errors = 0; - } - - if (__preheat_errors > 5) - { - if (farm_mode) { prusa_statistics(0); } - temp_runaway_stop(true); - if (farm_mode) { prusa_statistics(91); } - } - __preheat_start = _current_temperature; - __preheat_counter = 0; - } - } - } - - if (_current_temperature >= _target_temperature && temp_runaway_status[_heater_id] == TempRunaway_PREHEAT) - { - temp_runaway_status[_heater_id] = TempRunaway_ACTIVE; - temp_runaway_check_active = false; - } - - if (!temp_runaway_check_active && _output > 0) - { - temp_runaway_check_active = true; - } - - - if (temp_runaway_check_active) - { - // we are in range - if (_target_temperature - __hysteresis < _current_temperature && _current_temperature < _target_temperature + __hysteresis) - { - temp_runaway_check_active = false; - temp_runaway_error_counter[_heater_id] = 0; - } - else - { - if (temp_runaway_status[_heater_id] > TempRunaway_PREHEAT) - { - temp_runaway_error_counter[_heater_id]++; - if (temp_runaway_error_counter[_heater_id] * 2 > __timeout) - { - if (farm_mode) { prusa_statistics(0); } - temp_runaway_stop(false); - if (farm_mode) { prusa_statistics(90); } - } - } - } - } - - } -} - -void temp_runaway_stop(bool isPreheat) -{ - cancel_heatup = true; - quickStop(); - if (card.sdprinting) - { - card.sdprinting = false; - card.closefile(); - } - - disable_heater(); - disable_x(); - disable_y(); - disable_e0(); - disable_e1(); - disable_e2(); - manage_heater(); - lcd_update(); - WRITE(BEEPER, HIGH); - delayMicroseconds(500); - WRITE(BEEPER, LOW); - delayMicroseconds(100); - - if (isPreheat) - { - Stop(); - LCD_ALERTMESSAGEPGM(" PREHEAT ERROR"); - SERIAL_ERROR_START; - SERIAL_ERRORLNPGM(": THERMAL RUNAWAY ( PREHEAT )"); - SET_OUTPUT(EXTRUDER_0_AUTO_FAN_PIN); - SET_OUTPUT(FAN_PIN); - WRITE(EXTRUDER_0_AUTO_FAN_PIN, 1); - analogWrite(FAN_PIN, 255); - fanSpeed = 255; - delayMicroseconds(2000); - } - else - { - LCD_ALERTMESSAGEPGM("THERMAL RUNAWAY"); - SERIAL_ERROR_START; - SERIAL_ERRORLNPGM(": THERMAL RUNAWAY"); - } -} -#endif - - -void disable_heater() -{ - for(int i=0;i -1 - target_temperature[0]=0; - soft_pwm[0]=0; - #if defined(HEATER_0_PIN) && HEATER_0_PIN > -1 - WRITE(HEATER_0_PIN,LOW); - #endif - #endif - - #if defined(TEMP_1_PIN) && TEMP_1_PIN > -1 && EXTRUDERS > 1 - target_temperature[1]=0; - soft_pwm[1]=0; - #if defined(HEATER_1_PIN) && HEATER_1_PIN > -1 - WRITE(HEATER_1_PIN,LOW); - #endif - #endif - - #if defined(TEMP_2_PIN) && TEMP_2_PIN > -1 && EXTRUDERS > 2 - target_temperature[2]=0; - soft_pwm[2]=0; - #if defined(HEATER_2_PIN) && HEATER_2_PIN > -1 - WRITE(HEATER_2_PIN,LOW); - #endif - #endif - - #if defined(TEMP_BED_PIN) && TEMP_BED_PIN > -1 - target_temperature_bed=0; - soft_pwm_bed=0; - #if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1 - WRITE(HEATER_BED_PIN,LOW); - #endif - #endif -} - -void max_temp_error(uint8_t e) { - disable_heater(); - if(IsStopped() == false) { - SERIAL_ERROR_START; - SERIAL_ERRORLN((int)e); - SERIAL_ERRORLNPGM(": Extruder switched off. MAXTEMP triggered !"); - LCD_ALERTMESSAGEPGM("Err: MAXTEMP"); - } - #ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE - Stop(); - - - - #endif - SET_OUTPUT(EXTRUDER_0_AUTO_FAN_PIN); - SET_OUTPUT(FAN_PIN); - SET_OUTPUT(BEEPER); - WRITE(FAN_PIN, 1); - WRITE(EXTRUDER_0_AUTO_FAN_PIN, 1); - WRITE(BEEPER, 1); - // fanSpeed will consumed by the check_axes_activity() routine. - fanSpeed=255; - if (farm_mode) { prusa_statistics(93); } -} - -void min_temp_error(uint8_t e) { - disable_heater(); - if(IsStopped() == false) { - SERIAL_ERROR_START; - SERIAL_ERRORLN((int)e); - SERIAL_ERRORLNPGM(": Extruder switched off. MINTEMP triggered !"); - LCD_ALERTMESSAGEPGM("Err: MINTEMP"); - } - #ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE - Stop(); - #endif - if (farm_mode) { prusa_statistics(92); } - -} - -void bed_max_temp_error(void) { -#if HEATER_BED_PIN > -1 - WRITE(HEATER_BED_PIN, 0); -#endif - if(IsStopped() == false) { - SERIAL_ERROR_START; - SERIAL_ERRORLNPGM("Temperature heated bed switched off. MAXTEMP triggered !"); - LCD_ALERTMESSAGEPGM("Err: MAXTEMP BED"); - } - #ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE - Stop(); - #endif - -} - -void bed_min_temp_error(void) { -#if HEATER_BED_PIN > -1 - WRITE(HEATER_BED_PIN, 0); -#endif - if(IsStopped() == false) { - SERIAL_ERROR_START; - SERIAL_ERRORLNPGM("Temperature heated bed switched off. MINTEMP triggered !"); - LCD_ALERTMESSAGEPGM("Err: MINTEMP BED"); - } -#ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE - Stop(); -#endif -} - -#ifdef HEATER_0_USES_MAX6675 -#define MAX6675_HEAT_INTERVAL 250 -long max6675_previous_millis = MAX6675_HEAT_INTERVAL; -int max6675_temp = 2000; - -int read_max6675() -{ - if (millis() - max6675_previous_millis < MAX6675_HEAT_INTERVAL) - return max6675_temp; - - max6675_previous_millis = millis(); - max6675_temp = 0; - - #ifdef PRR - PRR &= ~(1<> 3; - } - - return max6675_temp; -} -#endif - - -// Timer 0 is shared with millies -ISR(TIMER0_COMPB_vect) -{ - //these variables are only accesible from the ISR, but static, so they don't lose their value - static unsigned char temp_count = 0; - static unsigned long raw_temp_0_value = 0; - static unsigned long raw_temp_1_value = 0; - static unsigned long raw_temp_2_value = 0; - static unsigned long raw_temp_bed_value = 0; - static unsigned char temp_state = 10; - static unsigned char pwm_count = (1 << SOFT_PWM_SCALE); - static unsigned char soft_pwm_0; -#ifdef SLOW_PWM_HEATERS - static unsigned char slow_pwm_count = 0; - static unsigned char state_heater_0 = 0; - static unsigned char state_timer_heater_0 = 0; -#endif -#if (EXTRUDERS > 1) || defined(HEATERS_PARALLEL) - static unsigned char soft_pwm_1; -#ifdef SLOW_PWM_HEATERS - static unsigned char state_heater_1 = 0; - static unsigned char state_timer_heater_1 = 0; -#endif -#endif -#if EXTRUDERS > 2 - static unsigned char soft_pwm_2; -#ifdef SLOW_PWM_HEATERS - static unsigned char state_heater_2 = 0; - static unsigned char state_timer_heater_2 = 0; -#endif -#endif -#if HEATER_BED_PIN > -1 - static unsigned char soft_pwm_b; -#ifdef SLOW_PWM_HEATERS - static unsigned char state_heater_b = 0; - static unsigned char state_timer_heater_b = 0; -#endif -#endif - -#if defined(FILWIDTH_PIN) &&(FILWIDTH_PIN > -1) - static unsigned long raw_filwidth_value = 0; //added for filament width sensor -#endif - -#ifndef SLOW_PWM_HEATERS - /* - * standard PWM modulation - */ - if(pwm_count == 0){ - soft_pwm_0 = soft_pwm[0]; - if(soft_pwm_0 > 0) { - WRITE(HEATER_0_PIN,1); -#ifdef HEATERS_PARALLEL - WRITE(HEATER_1_PIN,1); -#endif - } else WRITE(HEATER_0_PIN,0); - -#if EXTRUDERS > 1 - soft_pwm_1 = soft_pwm[1]; - if(soft_pwm_1 > 0) WRITE(HEATER_1_PIN,1); else WRITE(HEATER_1_PIN,0); -#endif -#if EXTRUDERS > 2 - soft_pwm_2 = soft_pwm[2]; - if(soft_pwm_2 > 0) WRITE(HEATER_2_PIN,1); else WRITE(HEATER_2_PIN,0); -#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); -#endif -#ifdef FAN_SOFT_PWM - soft_pwm_fan = fanSpeedSoftPwm / 2; - if(soft_pwm_fan > 0) WRITE(FAN_PIN,1); else WRITE(FAN_PIN,0); -#endif - } - if(soft_pwm_0 < pwm_count) { - WRITE(HEATER_0_PIN,0); -#ifdef HEATERS_PARALLEL - WRITE(HEATER_1_PIN,0); -#endif - } -#if EXTRUDERS > 1 - if(soft_pwm_1 < pwm_count) WRITE(HEATER_1_PIN,0); -#endif -#if EXTRUDERS > 2 - if(soft_pwm_2 < pwm_count) WRITE(HEATER_2_PIN,0); -#endif -#if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1 - if(soft_pwm_b < pwm_count) WRITE(HEATER_BED_PIN,0); -#endif -#ifdef FAN_SOFT_PWM - if(soft_pwm_fan < pwm_count) WRITE(FAN_PIN,0); -#endif - - pwm_count += (1 << SOFT_PWM_SCALE); - pwm_count &= 0x7f; - -#else //ifndef SLOW_PWM_HEATERS - /* - * SLOW PWM HEATERS - * - * for heaters drived by relay - */ -#ifndef MIN_STATE_TIME -#define MIN_STATE_TIME 16 // MIN_STATE_TIME * 65.5 = time in milliseconds -#endif - if (slow_pwm_count == 0) { - // EXTRUDER 0 - soft_pwm_0 = soft_pwm[0]; - if (soft_pwm_0 > 0) { - // turn ON heather only if the minimum time is up - if (state_timer_heater_0 == 0) { - // if change state set timer - if (state_heater_0 == 0) { - state_timer_heater_0 = MIN_STATE_TIME; - } - state_heater_0 = 1; - WRITE(HEATER_0_PIN, 1); -#ifdef HEATERS_PARALLEL - WRITE(HEATER_1_PIN, 1); -#endif - } - } else { - // turn OFF heather only if the minimum time is up - if (state_timer_heater_0 == 0) { - // if change state set timer - if (state_heater_0 == 1) { - state_timer_heater_0 = MIN_STATE_TIME; - } - state_heater_0 = 0; - WRITE(HEATER_0_PIN, 0); -#ifdef HEATERS_PARALLEL - WRITE(HEATER_1_PIN, 0); -#endif - } - } - -#if EXTRUDERS > 1 - // EXTRUDER 1 - soft_pwm_1 = soft_pwm[1]; - if (soft_pwm_1 > 0) { - // turn ON heather only if the minimum time is up - if (state_timer_heater_1 == 0) { - // if change state set timer - if (state_heater_1 == 0) { - state_timer_heater_1 = MIN_STATE_TIME; - } - state_heater_1 = 1; - WRITE(HEATER_1_PIN, 1); - } - } else { - // turn OFF heather only if the minimum time is up - if (state_timer_heater_1 == 0) { - // if change state set timer - if (state_heater_1 == 1) { - state_timer_heater_1 = MIN_STATE_TIME; - } - state_heater_1 = 0; - WRITE(HEATER_1_PIN, 0); - } - } -#endif - -#if EXTRUDERS > 2 - // EXTRUDER 2 - soft_pwm_2 = soft_pwm[2]; - if (soft_pwm_2 > 0) { - // turn ON heather only if the minimum time is up - if (state_timer_heater_2 == 0) { - // if change state set timer - if (state_heater_2 == 0) { - state_timer_heater_2 = MIN_STATE_TIME; - } - state_heater_2 = 1; - WRITE(HEATER_2_PIN, 1); - } - } else { - // turn OFF heather only if the minimum time is up - if (state_timer_heater_2 == 0) { - // if change state set timer - if (state_heater_2 == 1) { - state_timer_heater_2 = MIN_STATE_TIME; - } - state_heater_2 = 0; - WRITE(HEATER_2_PIN, 0); - } - } -#endif - -#if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1 - // BED - soft_pwm_b = soft_pwm_bed; - if (soft_pwm_b > 0) { - // turn ON heather only if the minimum time is up - if (state_timer_heater_b == 0) { - // if change state set timer - if (state_heater_b == 0) { - state_timer_heater_b = MIN_STATE_TIME; - } - state_heater_b = 1; - WRITE(HEATER_BED_PIN, 1); - } - } else { - // turn OFF heather only if the minimum time is up - if (state_timer_heater_b == 0) { - // if change state set timer - if (state_heater_b == 1) { - state_timer_heater_b = MIN_STATE_TIME; - } - state_heater_b = 0; - WRITE(HEATER_BED_PIN, 0); - } - } -#endif - } // if (slow_pwm_count == 0) - - // EXTRUDER 0 - if (soft_pwm_0 < slow_pwm_count) { - // turn OFF heather only if the minimum time is up - if (state_timer_heater_0 == 0) { - // if change state set timer - if (state_heater_0 == 1) { - state_timer_heater_0 = MIN_STATE_TIME; - } - state_heater_0 = 0; - WRITE(HEATER_0_PIN, 0); -#ifdef HEATERS_PARALLEL - WRITE(HEATER_1_PIN, 0); -#endif - } - } - -#if EXTRUDERS > 1 - // EXTRUDER 1 - if (soft_pwm_1 < slow_pwm_count) { - // turn OFF heather only if the minimum time is up - if (state_timer_heater_1 == 0) { - // if change state set timer - if (state_heater_1 == 1) { - state_timer_heater_1 = MIN_STATE_TIME; - } - state_heater_1 = 0; - WRITE(HEATER_1_PIN, 0); - } - } -#endif - -#if EXTRUDERS > 2 - // EXTRUDER 2 - if (soft_pwm_2 < slow_pwm_count) { - // turn OFF heather only if the minimum time is up - if (state_timer_heater_2 == 0) { - // if change state set timer - if (state_heater_2 == 1) { - state_timer_heater_2 = MIN_STATE_TIME; - } - state_heater_2 = 0; - WRITE(HEATER_2_PIN, 0); - } - } -#endif - -#if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1 - // BED - if (soft_pwm_b < slow_pwm_count) { - // turn OFF heather only if the minimum time is up - if (state_timer_heater_b == 0) { - // if change state set timer - if (state_heater_b == 1) { - state_timer_heater_b = MIN_STATE_TIME; - } - state_heater_b = 0; - WRITE(HEATER_BED_PIN, 0); - } - } -#endif - -#ifdef FAN_SOFT_PWM - if (pwm_count == 0){ - soft_pwm_fan = fanSpeedSoftPwm / 2; - if (soft_pwm_fan > 0) WRITE(FAN_PIN,1); else WRITE(FAN_PIN,0); - } - if (soft_pwm_fan < pwm_count) WRITE(FAN_PIN,0); -#endif - - pwm_count += (1 << SOFT_PWM_SCALE); - pwm_count &= 0x7f; - - // increment slow_pwm_count only every 64 pwm_count circa 65.5ms - if ((pwm_count % 64) == 0) { - slow_pwm_count++; - slow_pwm_count &= 0x7f; - - // Extruder 0 - if (state_timer_heater_0 > 0) { - state_timer_heater_0--; - } - -#if EXTRUDERS > 1 - // Extruder 1 - if (state_timer_heater_1 > 0) - state_timer_heater_1--; -#endif - -#if EXTRUDERS > 2 - // Extruder 2 - if (state_timer_heater_2 > 0) - state_timer_heater_2--; -#endif - -#if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1 - // Bed - if (state_timer_heater_b > 0) - state_timer_heater_b--; -#endif - } //if ((pwm_count % 64) == 0) { - -#endif //ifndef SLOW_PWM_HEATERS - - switch(temp_state) { - case 0: // Prepare TEMP_0 - #if defined(TEMP_0_PIN) && (TEMP_0_PIN > -1) - #if TEMP_0_PIN > 7 - ADCSRB = 1< -1) - raw_temp_0_value += ADC; - #endif - #ifdef HEATER_0_USES_MAX6675 // TODO remove the blocking - raw_temp_0_value = read_max6675(); - #endif - temp_state = 2; - break; - case 2: // Prepare TEMP_BED - #if defined(TEMP_BED_PIN) && (TEMP_BED_PIN > -1) - #if TEMP_BED_PIN > 7 - ADCSRB = 1< -1) - raw_temp_bed_value += ADC; - #endif - temp_state = 4; - break; - case 4: // Prepare TEMP_1 - #if defined(TEMP_1_PIN) && (TEMP_1_PIN > -1) - #if TEMP_1_PIN > 7 - ADCSRB = 1< -1) - raw_temp_1_value += ADC; - #endif - temp_state = 6; - break; - case 6: // Prepare TEMP_2 - #if defined(TEMP_2_PIN) && (TEMP_2_PIN > -1) - #if TEMP_2_PIN > 7 - ADCSRB = 1< -1) - raw_temp_2_value += ADC; - #endif - temp_state = 8;//change so that Filament Width is also measured - - break; - case 8: //Prepare FILWIDTH - #if defined(FILWIDTH_PIN) && (FILWIDTH_PIN> -1) - #if FILWIDTH_PIN>7 - ADCSRB = 1< -1) - //raw_filwidth_value += ADC; //remove to use an IIR filter approach - if(ADC>102) //check that ADC is reading a voltage > 0.5 volts, otherwise don't take in the data. - { - raw_filwidth_value= raw_filwidth_value-(raw_filwidth_value>>7); //multipliy raw_filwidth_value by 127/128 - - raw_filwidth_value= raw_filwidth_value + ((unsigned long)ADC<<7); //add new ADC reading - } - #endif - temp_state = 0; - - temp_count++; - break; - - - case 10: //Startup, delay initial temp reading a tiny bit so the hardware can settle. - temp_state = 0; - break; -// default: -// SERIAL_ERROR_START; -// SERIAL_ERRORLNPGM("Temp measurement error!"); -// break; - } - - if(temp_count >= OVERSAMPLENR) // 10 * 16 * 1/(16000000/64/256) = 164ms. - { - if (!temp_meas_ready) //Only update the raw values if they have been read. Else we could be updating them during reading. - { - current_temperature_raw[0] = raw_temp_0_value; -#if EXTRUDERS > 1 - current_temperature_raw[1] = raw_temp_1_value; -#endif -#ifdef TEMP_SENSOR_1_AS_REDUNDANT - redundant_temperature_raw = raw_temp_1_value; -#endif -#if EXTRUDERS > 2 - current_temperature_raw[2] = raw_temp_2_value; -#endif - current_temperature_bed_raw = raw_temp_bed_value; - } - -//Add similar code for Filament Sensor - can be read any time since IIR filtering is used -#if defined(FILWIDTH_PIN) &&(FILWIDTH_PIN > -1) - current_raw_filwidth = raw_filwidth_value>>10; //need to divide to get to 0-16384 range since we used 1/128 IIR filter approach -#endif - - - temp_meas_ready = true; - temp_count = 0; - raw_temp_0_value = 0; - raw_temp_1_value = 0; - raw_temp_2_value = 0; - raw_temp_bed_value = 0; - -#if HEATER_0_RAW_LO_TEMP > HEATER_0_RAW_HI_TEMP - if(current_temperature_raw[0] <= maxttemp_raw[0]) { -#else - if(current_temperature_raw[0] >= maxttemp_raw[0]) { -#endif - max_temp_error(0); - } -#if HEATER_0_RAW_LO_TEMP > HEATER_0_RAW_HI_TEMP - if(current_temperature_raw[0] >= minttemp_raw[0]) { -#else - if(current_temperature_raw[0] <= minttemp_raw[0]) { -#endif - min_temp_error(0); - } -#if EXTRUDERS > 1 -#if HEATER_1_RAW_LO_TEMP > HEATER_1_RAW_HI_TEMP - if(current_temperature_raw[1] <= maxttemp_raw[1]) { -#else - if(current_temperature_raw[1] >= maxttemp_raw[1]) { -#endif - max_temp_error(1); - } -#if HEATER_1_RAW_LO_TEMP > HEATER_1_RAW_HI_TEMP - if(current_temperature_raw[1] >= minttemp_raw[1]) { -#else - if(current_temperature_raw[1] <= minttemp_raw[1]) { -#endif - min_temp_error(1); - } -#endif -#if EXTRUDERS > 2 -#if HEATER_2_RAW_LO_TEMP > HEATER_2_RAW_HI_TEMP - if(current_temperature_raw[2] <= maxttemp_raw[2]) { -#else - if(current_temperature_raw[2] >= maxttemp_raw[2]) { -#endif - max_temp_error(2); - } -#if HEATER_2_RAW_LO_TEMP > HEATER_2_RAW_HI_TEMP - if(current_temperature_raw[2] >= minttemp_raw[2]) { -#else - if(current_temperature_raw[2] <= minttemp_raw[2]) { -#endif - min_temp_error(2); - } -#endif - - /* No bed MINTEMP error? */ - - -#if defined(BED_MAXTEMP) && (TEMP_SENSOR_BED != 0) -# if HEATER_BED_RAW_LO_TEMP > HEATER_BED_RAW_HI_TEMP - if(current_temperature_bed_raw <= bed_maxttemp_raw) { -#else - if(current_temperature_bed_raw >= bed_maxttemp_raw) { -#endif - target_temperature_bed = 0; - bed_max_temp_error(); - } - } - -# if HEATER_BED_RAW_LO_TEMP > HEATER_BED_RAW_HI_TEMP - if(current_temperature_bed_raw >= bed_minttemp_raw) { -#else - if(current_temperature_bed_raw <= bed_minttemp_raw) { -#endif - bed_min_temp_error(); - } - -#endif - -#ifdef BABYSTEPPING - for(uint8_t axis=0;axis<3;axis++) - { - int curTodo=babystepsTodo[axis]; //get rid of volatile for performance - - if(curTodo>0) - { - babystep(axis,/*fwd*/true); - babystepsTodo[axis]--; //less to do next time - } - else - if(curTodo<0) - { - babystep(axis,/*fwd*/false); - babystepsTodo[axis]++; //less to do next time - } - } -#endif //BABYSTEPPING -} - -#ifdef PIDTEMP -// Apply the scale factors to the PID values - - -float scalePID_i(float i) -{ - return i*PID_dT; -} - -float unscalePID_i(float i) -{ - return i/PID_dT; -} - -float scalePID_d(float d) -{ - return d/PID_dT; -} - -float unscalePID_d(float d) -{ - return d*PID_dT; -} - -#endif //PIDTEMP - - + checkExtruderAutoFans(); + extruder_autofan_last_check = millis(); + } + #endif + + #ifndef PIDTEMPBED + if(millis() - previous_millis_bed_heater < BED_CHECK_INTERVAL) + return; + previous_millis_bed_heater = millis(); + #endif + + #if TEMP_SENSOR_BED != 0 + + #ifdef PIDTEMPBED + pid_input = current_temperature_bed; + + #ifndef PID_OPENLOOP + pid_error_bed = target_temperature_bed - pid_input; + pTerm_bed = bedKp * pid_error_bed; + temp_iState_bed += pid_error_bed; + temp_iState_bed = constrain(temp_iState_bed, temp_iState_min_bed, temp_iState_max_bed); + iTerm_bed = bedKi * temp_iState_bed; + + //K1 defined in Configuration.h in the PID settings + #define K2 (1.0-K1) + dTerm_bed= (bedKd * (pid_input - temp_dState_bed))*K2 + (K1 * dTerm_bed); + temp_dState_bed = pid_input; + + pid_output = pTerm_bed + iTerm_bed - dTerm_bed; + if (pid_output > MAX_BED_POWER) { + if (pid_error_bed > 0 ) temp_iState_bed -= pid_error_bed; // conditional un-integration + pid_output=MAX_BED_POWER; + } else if (pid_output < 0){ + if (pid_error_bed < 0 ) temp_iState_bed -= pid_error_bed; // conditional un-integration + pid_output=0; + } + + #else + pid_output = constrain(target_temperature_bed, 0, MAX_BED_POWER); + #endif //PID_OPENLOOP + + if((current_temperature_bed > BED_MINTEMP) && (current_temperature_bed < BED_MAXTEMP)) + { + soft_pwm_bed = (int)pid_output >> 1; + } + else { + soft_pwm_bed = 0; + } + + #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 >= target_temperature_bed) + { + soft_pwm_bed = 0; + } + else + { + soft_pwm_bed = MAX_BED_POWER>>1; + } + } + else + { + soft_pwm_bed = 0; + 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 > target_temperature_bed + BED_HYSTERESIS) + { + soft_pwm_bed = 0; + } + else if(current_temperature_bed <= target_temperature_bed - BED_HYSTERESIS) + { + soft_pwm_bed = MAX_BED_POWER>>1; + } + } + else + { + soft_pwm_bed = 0; + WRITE(HEATER_BED_PIN,LOW); + } + #endif + #endif + +//code for controlling the extruder rate based on the width sensor +#ifdef FILAMENT_SENSOR + if(filament_sensor) + { + meas_shift_index=delay_index1-meas_delay_cm; + if(meas_shift_index<0) + meas_shift_index = meas_shift_index + (MAX_MEASUREMENT_DELAY+1); //loop around buffer if needed + + //get the delayed info and add 100 to reconstitute to a percent of the nominal filament diameter + //then square it to get an area + + if(meas_shift_index<0) + meas_shift_index=0; + else if (meas_shift_index>MAX_MEASUREMENT_DELAY) + meas_shift_index=MAX_MEASUREMENT_DELAY; + + volumetric_multiplier[FILAMENT_SENSOR_EXTRUDER_NUM] = pow((float)(100+measurement_delay[meas_shift_index])/100.0,2); + if (volumetric_multiplier[FILAMENT_SENSOR_EXTRUDER_NUM] <0.01) + volumetric_multiplier[FILAMENT_SENSOR_EXTRUDER_NUM]=0.01; + } +#endif +} + +#define PGM_RD_W(x) (short)pgm_read_word(&x) +// Derived from RepRap FiveD extruder::getTemperature() +// For hot end temperature measurement. +static float analog2temp(int raw, uint8_t e) { +#ifdef TEMP_SENSOR_1_AS_REDUNDANT + if(e > EXTRUDERS) +#else + if(e >= EXTRUDERS) +#endif + { + SERIAL_ERROR_START; + SERIAL_ERROR((int)e); + SERIAL_ERRORLNPGM(" - Invalid extruder number !"); + kill(); + return 0.0; + } + #ifdef HEATER_0_USES_MAX6675 + if (e == 0) + { + return 0.25 * raw; + } + #endif + + if(heater_ttbl_map[e] != NULL) + { + float celsius = 0; + uint8_t i; + short (*tt)[][2] = (short (*)[][2])(heater_ttbl_map[e]); + + for (i=1; i raw) + { + celsius = PGM_RD_W((*tt)[i-1][1]) + + (raw - PGM_RD_W((*tt)[i-1][0])) * + (float)(PGM_RD_W((*tt)[i][1]) - PGM_RD_W((*tt)[i-1][1])) / + (float)(PGM_RD_W((*tt)[i][0]) - PGM_RD_W((*tt)[i-1][0])); + break; + } + } + + // Overflow: Set to last value in the table + if (i == heater_ttbllen_map[e]) celsius = PGM_RD_W((*tt)[i-1][1]); + + return celsius; + } + return ((raw * ((5.0 * 100.0) / 1024.0) / OVERSAMPLENR) * TEMP_SENSOR_AD595_GAIN) + TEMP_SENSOR_AD595_OFFSET; +} + +// Derived from RepRap FiveD extruder::getTemperature() +// For bed temperature measurement. +static float analog2tempBed(int raw) { + #ifdef BED_USES_THERMISTOR + float celsius = 0; + byte i; + + for (i=1; i raw) + { + celsius = PGM_RD_W(BEDTEMPTABLE[i-1][1]) + + (raw - PGM_RD_W(BEDTEMPTABLE[i-1][0])) * + (float)(PGM_RD_W(BEDTEMPTABLE[i][1]) - PGM_RD_W(BEDTEMPTABLE[i-1][1])) / + (float)(PGM_RD_W(BEDTEMPTABLE[i][0]) - PGM_RD_W(BEDTEMPTABLE[i-1][0])); + break; + } + } + + // Overflow: Set to last value in the table + if (i == BEDTEMPTABLE_LEN) celsius = PGM_RD_W(BEDTEMPTABLE[i-1][1]); + + + // temperature offset adjustment +#ifdef BED_OFFSET + float _offset = BED_OFFSET; + float _offset_center = BED_OFFSET_CENTER; + float _offset_start = BED_OFFSET_START; + float _first_koef = (_offset / 2) / (_offset_center - _offset_start); + float _second_koef = (_offset / 2) / (100 - _offset_center); + + + if (celsius >= _offset_start && celsius <= _offset_center) + { + celsius = celsius + (_first_koef * (celsius - _offset_start)); + } + else if (celsius > _offset_center && celsius <= 100) + { + celsius = celsius + (_first_koef * (_offset_center - _offset_start)) + ( _second_koef * ( celsius - ( 100 - _offset_center ) )) ; + } + else if (celsius > 100) + { + celsius = celsius + _offset; + } +#endif + + + return celsius; + #elif defined BED_USES_AD595 + return ((raw * ((5.0 * 100.0) / 1024.0) / OVERSAMPLENR) * TEMP_SENSOR_AD595_GAIN) + TEMP_SENSOR_AD595_OFFSET; + #else + return 0; + #endif +} + +/* Called to get the raw values into the the actual temperatures. The raw values are created in interrupt context, + and this function is called from normal context as it is too slow to run in interrupts and will block the stepper routine otherwise */ +static void updateTemperaturesFromRawValues() +{ + for(uint8_t e=0;e -1) //check if a sensor is supported + filament_width_meas = analog2widthFil(); + #endif + //Reset the watchdog after we know we have a temperature measurement. + watchdog_reset(); + + CRITICAL_SECTION_START; + temp_meas_ready = false; + CRITICAL_SECTION_END; +} + + +// For converting raw Filament Width to milimeters +#ifdef FILAMENT_SENSOR +float analog2widthFil() { +return current_raw_filwidth/16383.0*5.0; +//return current_raw_filwidth; +} + +// For converting raw Filament Width to a ratio +int widthFil_to_size_ratio() { + +float temp; + +temp=filament_width_meas; +if(filament_width_measMEASURED_UPPER_LIMIT) + temp= MEASURED_UPPER_LIMIT; + + +return(filament_width_nominal/temp*100); + + +} +#endif + + + + + +void tp_init() +{ +#if MB(RUMBA) && ((TEMP_SENSOR_0==-1)||(TEMP_SENSOR_1==-1)||(TEMP_SENSOR_2==-1)||(TEMP_SENSOR_BED==-1)) + //disable RUMBA JTAG in case the thermocouple extension is plugged on top of JTAG connector + MCUCR=(1< -1) + SET_OUTPUT(HEATER_0_PIN); + #endif + #if defined(HEATER_1_PIN) && (HEATER_1_PIN > -1) + SET_OUTPUT(HEATER_1_PIN); + #endif + #if defined(HEATER_2_PIN) && (HEATER_2_PIN > -1) + SET_OUTPUT(HEATER_2_PIN); + #endif + #if defined(HEATER_BED_PIN) && (HEATER_BED_PIN > -1) + SET_OUTPUT(HEATER_BED_PIN); + #endif + #if defined(FAN_PIN) && (FAN_PIN > -1) + SET_OUTPUT(FAN_PIN); + #ifdef FAST_PWM_FAN + setPwmFrequency(FAN_PIN, 1); // No prescaling. Pwm frequency = F_CPU/256/8 + #endif + #ifdef FAN_SOFT_PWM + soft_pwm_fan = fanSpeedSoftPwm / 2; + #endif + #endif + + #ifdef HEATER_0_USES_MAX6675 + #ifndef SDSUPPORT + SET_OUTPUT(SCK_PIN); + WRITE(SCK_PIN,0); + + SET_OUTPUT(MOSI_PIN); + WRITE(MOSI_PIN,1); + + SET_INPUT(MISO_PIN); + WRITE(MISO_PIN,1); + #endif + /* Using pinMode and digitalWrite, as that was the only way I could get it to compile */ + + //Have to toggle SD card CS pin to low first, to enable firmware to talk with SD card + pinMode(SS_PIN, OUTPUT); + digitalWrite(SS_PIN,0); + pinMode(MAX6675_SS, OUTPUT); + digitalWrite(MAX6675_SS,1); + #endif + + // Set analog inputs + ADCSRA = 1< -1) + #if TEMP_0_PIN < 8 + DIDR0 |= 1 << TEMP_0_PIN; + #else + DIDR2 |= 1<<(TEMP_0_PIN - 8); + #endif + #endif + #if defined(TEMP_1_PIN) && (TEMP_1_PIN > -1) + #if TEMP_1_PIN < 8 + DIDR0 |= 1< -1) + #if TEMP_2_PIN < 8 + DIDR0 |= 1 << TEMP_2_PIN; + #else + DIDR2 |= 1<<(TEMP_2_PIN - 8); + #endif + #endif + #if defined(TEMP_BED_PIN) && (TEMP_BED_PIN > -1) + #if TEMP_BED_PIN < 8 + DIDR0 |= 1< -1) + #if FILWIDTH_PIN < 8 + DIDR0 |= 1< HEATER_0_MAXTEMP) { +#if HEATER_0_RAW_LO_TEMP < HEATER_0_RAW_HI_TEMP + maxttemp_raw[0] -= OVERSAMPLENR; +#else + maxttemp_raw[0] += OVERSAMPLENR; +#endif + } +#endif //MAXTEMP + +#if (EXTRUDERS > 1) && defined(HEATER_1_MINTEMP) + minttemp[1] = HEATER_1_MINTEMP; + while(analog2temp(minttemp_raw[1], 1) < HEATER_1_MINTEMP) { +#if HEATER_1_RAW_LO_TEMP < HEATER_1_RAW_HI_TEMP + minttemp_raw[1] += OVERSAMPLENR; +#else + minttemp_raw[1] -= OVERSAMPLENR; +#endif + } +#endif // MINTEMP 1 +#if (EXTRUDERS > 1) && defined(HEATER_1_MAXTEMP) + maxttemp[1] = HEATER_1_MAXTEMP; + while(analog2temp(maxttemp_raw[1], 1) > HEATER_1_MAXTEMP) { +#if HEATER_1_RAW_LO_TEMP < HEATER_1_RAW_HI_TEMP + maxttemp_raw[1] -= OVERSAMPLENR; +#else + maxttemp_raw[1] += OVERSAMPLENR; +#endif + } +#endif //MAXTEMP 1 + +#if (EXTRUDERS > 2) && defined(HEATER_2_MINTEMP) + minttemp[2] = HEATER_2_MINTEMP; + while(analog2temp(minttemp_raw[2], 2) < HEATER_2_MINTEMP) { +#if HEATER_2_RAW_LO_TEMP < HEATER_2_RAW_HI_TEMP + minttemp_raw[2] += OVERSAMPLENR; +#else + minttemp_raw[2] -= OVERSAMPLENR; +#endif + } +#endif //MINTEMP 2 +#if (EXTRUDERS > 2) && defined(HEATER_2_MAXTEMP) + maxttemp[2] = HEATER_2_MAXTEMP; + while(analog2temp(maxttemp_raw[2], 2) > HEATER_2_MAXTEMP) { +#if HEATER_2_RAW_LO_TEMP < HEATER_2_RAW_HI_TEMP + maxttemp_raw[2] -= OVERSAMPLENR; +#else + maxttemp_raw[2] += OVERSAMPLENR; +#endif + } +#endif //MAXTEMP 2 + +#ifdef BED_MINTEMP + /* No bed MINTEMP error implemented?!? */ + while(analog2tempBed(bed_minttemp_raw) < BED_MINTEMP) { +#if HEATER_BED_RAW_LO_TEMP < HEATER_BED_RAW_HI_TEMP + bed_minttemp_raw += OVERSAMPLENR; +#else + bed_minttemp_raw -= OVERSAMPLENR; +#endif + } + +#endif //BED_MINTEMP +#ifdef BED_MAXTEMP + while(analog2tempBed(bed_maxttemp_raw) > BED_MAXTEMP) { +#if HEATER_BED_RAW_LO_TEMP < HEATER_BED_RAW_HI_TEMP + bed_maxttemp_raw -= OVERSAMPLENR; +#else + bed_maxttemp_raw += OVERSAMPLENR; +#endif + } +#endif //BED_MAXTEMP +} + +void setWatch() +{ +#ifdef WATCH_TEMP_PERIOD + for (int e = 0; e < EXTRUDERS; e++) + { + if(degHotend(e) < degTargetHotend(e) - (WATCH_TEMP_INCREASE * 2)) + { + watch_start_temp[e] = degHotend(e); + watchmillis[e] = millis(); + } + } +#endif +} + +#if (defined (TEMP_RUNAWAY_BED_HYSTERESIS) && TEMP_RUNAWAY_BED_TIMEOUT > 0) || (defined (TEMP_RUNAWAY_EXTRUDER_HYSTERESIS) && TEMP_RUNAWAY_EXTRUDER_TIMEOUT > 0) +void temp_runaway_check(int _heater_id, float _target_temperature, float _current_temperature, float _output, bool _isbed) +{ + float __hysteresis = 0; + int __timeout = 0; + bool temp_runaway_check_active = false; + static float __preheat_start[2] = { 0,0}; //currently just bed and one extruder + static int __preheat_counter[2] = { 0,0}; + static int __preheat_errors[2] = { 0,0}; + + +#ifdef TEMP_RUNAWAY_BED_TIMEOUT + if (_isbed) + { + __hysteresis = TEMP_RUNAWAY_BED_HYSTERESIS; + __timeout = TEMP_RUNAWAY_BED_TIMEOUT; + } +#endif +#ifdef TEMP_RUNAWAY_EXTRUDER_TIMEOUT + if (!_isbed) + { + __hysteresis = TEMP_RUNAWAY_EXTRUDER_HYSTERESIS; + __timeout = TEMP_RUNAWAY_EXTRUDER_TIMEOUT; + } +#endif + + if (millis() - temp_runaway_timer[_heater_id] > 2000) + { + + temp_runaway_timer[_heater_id] = millis(); + if (_output == 0) + { + temp_runaway_check_active = false; + temp_runaway_error_counter[_heater_id] = 0; + } + + if (temp_runaway_target[_heater_id] != _target_temperature) + { + if (_target_temperature > 0) + { + temp_runaway_status[_heater_id] = TempRunaway_PREHEAT; + temp_runaway_target[_heater_id] = _target_temperature; + __preheat_start[_heater_id] = _current_temperature; + __preheat_counter[_heater_id] = 0; + } + else + { + temp_runaway_status[_heater_id] = TempRunaway_INACTIVE; + temp_runaway_target[_heater_id] = _target_temperature; + } + } + + if (temp_runaway_status[_heater_id] == TempRunaway_PREHEAT) + { + if (_current_temperature < ((_isbed) ? (0.8 * _target_temperature) : 150)) //check only in area where temperature is changing fastly for heater, check to 0.8 x target temperature for bed + { + __preheat_counter[_heater_id]++; + if (__preheat_counter[_heater_id] > ((_isbed) ? 16 : 8)) // periodicaly check if current temperature changes + { + /*SERIAL_ECHOPGM("Heater:"); + MYSERIAL.print(_heater_id); + SERIAL_ECHOPGM(" T:"); + MYSERIAL.print(_current_temperature); + SERIAL_ECHOPGM(" Tstart:"); + MYSERIAL.print(__preheat_start[_heater_id]);*/ + + if (_current_temperature - __preheat_start[_heater_id] < 2) { + __preheat_errors[_heater_id]++; + /*SERIAL_ECHOPGM(" Preheat errors:"); + MYSERIAL.println(__preheat_errors[_heater_id]);*/ + } + else { + //SERIAL_ECHOLNPGM(""); + __preheat_errors[_heater_id] = 0; + } + + if (__preheat_errors[_heater_id] > ((_isbed) ? 2 : 5)) + { + if (farm_mode) { prusa_statistics(0); } + temp_runaway_stop(true, _isbed); + if (farm_mode) { prusa_statistics(91); } + } + __preheat_start[_heater_id] = _current_temperature; + __preheat_counter[_heater_id] = 0; + } + } + } + + if (_current_temperature >= _target_temperature && temp_runaway_status[_heater_id] == TempRunaway_PREHEAT) + { + temp_runaway_status[_heater_id] = TempRunaway_ACTIVE; + temp_runaway_check_active = false; + } + + if (!temp_runaway_check_active && _output > 0) + { + temp_runaway_check_active = true; + } + + + if (temp_runaway_check_active) + { + // we are in range + if (_target_temperature - __hysteresis < _current_temperature && _current_temperature < _target_temperature + __hysteresis) + { + temp_runaway_check_active = false; + temp_runaway_error_counter[_heater_id] = 0; + } + else + { + if (temp_runaway_status[_heater_id] > TempRunaway_PREHEAT) + { + temp_runaway_error_counter[_heater_id]++; + if (temp_runaway_error_counter[_heater_id] * 2 > __timeout) + { + if (farm_mode) { prusa_statistics(0); } + temp_runaway_stop(false, _isbed); + if (farm_mode) { prusa_statistics(90); } + } + } + } + } + + } +} + +void temp_runaway_stop(bool isPreheat, bool isBed) +{ + cancel_heatup = true; + quickStop(); + if (card.sdprinting) + { + card.sdprinting = false; + card.closefile(); + } + + disable_heater(); + disable_x(); + disable_y(); + disable_e0(); + disable_e1(); + disable_e2(); + manage_heater(); + lcd_update(); + WRITE(BEEPER, HIGH); + delayMicroseconds(500); + WRITE(BEEPER, LOW); + delayMicroseconds(100); + + if (isPreheat) + { + Stop(); + isBed ? LCD_ALERTMESSAGEPGM("BED PREHEAT ERROR") : LCD_ALERTMESSAGEPGM("PREHEAT ERROR"); + SERIAL_ERROR_START; + isBed ? SERIAL_ERRORLNPGM(" THERMAL RUNAWAY ( PREHEAT HEATBED)") : SERIAL_ERRORLNPGM(" THERMAL RUNAWAY ( PREHEAT HOTEND)"); + SET_OUTPUT(EXTRUDER_0_AUTO_FAN_PIN); + SET_OUTPUT(FAN_PIN); + WRITE(EXTRUDER_0_AUTO_FAN_PIN, 1); + analogWrite(FAN_PIN, 255); + fanSpeed = 255; + delayMicroseconds(2000); + } + else + { + isBed ? LCD_ALERTMESSAGEPGM("BED THERMAL RUNAWAY") : LCD_ALERTMESSAGEPGM("THERMAL RUNAWAY"); + SERIAL_ERROR_START; + isBed ? SERIAL_ERRORLNPGM(" HEATBED THERMAL RUNAWAY") : SERIAL_ERRORLNPGM(" HOTEND THERMAL RUNAWAY"); + } +} +#endif + + +void disable_heater() +{ + for(int i=0;i -1 + target_temperature[0]=0; + soft_pwm[0]=0; + #if defined(HEATER_0_PIN) && HEATER_0_PIN > -1 + WRITE(HEATER_0_PIN,LOW); + #endif + #endif + + #if defined(TEMP_1_PIN) && TEMP_1_PIN > -1 && EXTRUDERS > 1 + target_temperature[1]=0; + soft_pwm[1]=0; + #if defined(HEATER_1_PIN) && HEATER_1_PIN > -1 + WRITE(HEATER_1_PIN,LOW); + #endif + #endif + + #if defined(TEMP_2_PIN) && TEMP_2_PIN > -1 && EXTRUDERS > 2 + target_temperature[2]=0; + soft_pwm[2]=0; + #if defined(HEATER_2_PIN) && HEATER_2_PIN > -1 + WRITE(HEATER_2_PIN,LOW); + #endif + #endif + + #if defined(TEMP_BED_PIN) && TEMP_BED_PIN > -1 + target_temperature_bed=0; + soft_pwm_bed=0; + #if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1 + WRITE(HEATER_BED_PIN,LOW); + #endif + #endif +} + +void max_temp_error(uint8_t e) { + disable_heater(); + if(IsStopped() == false) { + SERIAL_ERROR_START; + SERIAL_ERRORLN((int)e); + SERIAL_ERRORLNPGM(": Extruder switched off. MAXTEMP triggered !"); + LCD_ALERTMESSAGEPGM("Err: MAXTEMP"); + } + #ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE + Stop(); + + + + #endif + SET_OUTPUT(EXTRUDER_0_AUTO_FAN_PIN); + SET_OUTPUT(FAN_PIN); + SET_OUTPUT(BEEPER); + WRITE(FAN_PIN, 1); + WRITE(EXTRUDER_0_AUTO_FAN_PIN, 1); + WRITE(BEEPER, 1); + // fanSpeed will consumed by the check_axes_activity() routine. + fanSpeed=255; + if (farm_mode) { prusa_statistics(93); } +} + +void min_temp_error(uint8_t e) { + disable_heater(); + if(IsStopped() == false) { + SERIAL_ERROR_START; + SERIAL_ERRORLN((int)e); + SERIAL_ERRORLNPGM(": Extruder switched off. MINTEMP triggered !"); + LCD_ALERTMESSAGEPGM("Err: MINTEMP"); + } + #ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE + Stop(); + #endif + if (farm_mode) { prusa_statistics(92); } + +} + +void bed_max_temp_error(void) { +#if HEATER_BED_PIN > -1 + WRITE(HEATER_BED_PIN, 0); +#endif + if(IsStopped() == false) { + SERIAL_ERROR_START; + SERIAL_ERRORLNPGM("Temperature heated bed switched off. MAXTEMP triggered !"); + LCD_ALERTMESSAGEPGM("Err: MAXTEMP BED"); + } + #ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE + Stop(); + #endif + +} + +void bed_min_temp_error(void) { +/*#if HEATER_BED_PIN > -1 + WRITE(HEATER_BED_PIN, 0); +#endif + if(IsStopped() == false) { + SERIAL_ERROR_START; + SERIAL_ERRORLNPGM("Temperature heated bed switched off. MINTEMP triggered !"); + LCD_ALERTMESSAGEPGM("Err: MINTEMP BED"); + } +#ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE + Stop(); +#endif*/ +} + +#ifdef HEATER_0_USES_MAX6675 +#define MAX6675_HEAT_INTERVAL 250 +long max6675_previous_millis = MAX6675_HEAT_INTERVAL; +int max6675_temp = 2000; + +int read_max6675() +{ + if (millis() - max6675_previous_millis < MAX6675_HEAT_INTERVAL) + return max6675_temp; + + max6675_previous_millis = millis(); + max6675_temp = 0; + + #ifdef PRR + PRR &= ~(1<> 3; + } + + return max6675_temp; +} +#endif + + +// Timer 0 is shared with millies +ISR(TIMER0_COMPB_vect) +{ + //these variables are only accesible from the ISR, but static, so they don't lose their value + static unsigned char temp_count = 0; + static unsigned long raw_temp_0_value = 0; + static unsigned long raw_temp_1_value = 0; + static unsigned long raw_temp_2_value = 0; + static unsigned long raw_temp_bed_value = 0; + static unsigned char temp_state = 10; + static unsigned char pwm_count = (1 << SOFT_PWM_SCALE); + static unsigned char soft_pwm_0; +#ifdef SLOW_PWM_HEATERS + static unsigned char slow_pwm_count = 0; + static unsigned char state_heater_0 = 0; + static unsigned char state_timer_heater_0 = 0; +#endif +#if (EXTRUDERS > 1) || defined(HEATERS_PARALLEL) + static unsigned char soft_pwm_1; +#ifdef SLOW_PWM_HEATERS + static unsigned char state_heater_1 = 0; + static unsigned char state_timer_heater_1 = 0; +#endif +#endif +#if EXTRUDERS > 2 + static unsigned char soft_pwm_2; +#ifdef SLOW_PWM_HEATERS + static unsigned char state_heater_2 = 0; + static unsigned char state_timer_heater_2 = 0; +#endif +#endif +#if HEATER_BED_PIN > -1 + static unsigned char soft_pwm_b; +#ifdef SLOW_PWM_HEATERS + static unsigned char state_heater_b = 0; + static unsigned char state_timer_heater_b = 0; +#endif +#endif + +#if defined(FILWIDTH_PIN) &&(FILWIDTH_PIN > -1) + static unsigned long raw_filwidth_value = 0; //added for filament width sensor +#endif + +#ifndef SLOW_PWM_HEATERS + /* + * standard PWM modulation + */ + if(pwm_count == 0){ + soft_pwm_0 = soft_pwm[0]; + if(soft_pwm_0 > 0) { + WRITE(HEATER_0_PIN,1); +#ifdef HEATERS_PARALLEL + WRITE(HEATER_1_PIN,1); +#endif + } else WRITE(HEATER_0_PIN,0); + +#if EXTRUDERS > 1 + soft_pwm_1 = soft_pwm[1]; + if(soft_pwm_1 > 0) WRITE(HEATER_1_PIN,1); else WRITE(HEATER_1_PIN,0); +#endif +#if EXTRUDERS > 2 + soft_pwm_2 = soft_pwm[2]; + if(soft_pwm_2 > 0) WRITE(HEATER_2_PIN,1); else WRITE(HEATER_2_PIN,0); +#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); +#endif +#ifdef FAN_SOFT_PWM + soft_pwm_fan = fanSpeedSoftPwm / 2; + if(soft_pwm_fan > 0) WRITE(FAN_PIN,1); else WRITE(FAN_PIN,0); +#endif + } + if(soft_pwm_0 < pwm_count) { + WRITE(HEATER_0_PIN,0); +#ifdef HEATERS_PARALLEL + WRITE(HEATER_1_PIN,0); +#endif + } +#if EXTRUDERS > 1 + if(soft_pwm_1 < pwm_count) WRITE(HEATER_1_PIN,0); +#endif +#if EXTRUDERS > 2 + if(soft_pwm_2 < pwm_count) WRITE(HEATER_2_PIN,0); +#endif +#if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1 + if(soft_pwm_b < pwm_count) WRITE(HEATER_BED_PIN,0); +#endif +#ifdef FAN_SOFT_PWM + if(soft_pwm_fan < pwm_count) WRITE(FAN_PIN,0); +#endif + + pwm_count += (1 << SOFT_PWM_SCALE); + pwm_count &= 0x7f; + +#else //ifndef SLOW_PWM_HEATERS + /* + * SLOW PWM HEATERS + * + * for heaters drived by relay + */ +#ifndef MIN_STATE_TIME +#define MIN_STATE_TIME 16 // MIN_STATE_TIME * 65.5 = time in milliseconds +#endif + if (slow_pwm_count == 0) { + // EXTRUDER 0 + soft_pwm_0 = soft_pwm[0]; + if (soft_pwm_0 > 0) { + // turn ON heather only if the minimum time is up + if (state_timer_heater_0 == 0) { + // if change state set timer + if (state_heater_0 == 0) { + state_timer_heater_0 = MIN_STATE_TIME; + } + state_heater_0 = 1; + WRITE(HEATER_0_PIN, 1); +#ifdef HEATERS_PARALLEL + WRITE(HEATER_1_PIN, 1); +#endif + } + } else { + // turn OFF heather only if the minimum time is up + if (state_timer_heater_0 == 0) { + // if change state set timer + if (state_heater_0 == 1) { + state_timer_heater_0 = MIN_STATE_TIME; + } + state_heater_0 = 0; + WRITE(HEATER_0_PIN, 0); +#ifdef HEATERS_PARALLEL + WRITE(HEATER_1_PIN, 0); +#endif + } + } + +#if EXTRUDERS > 1 + // EXTRUDER 1 + soft_pwm_1 = soft_pwm[1]; + if (soft_pwm_1 > 0) { + // turn ON heather only if the minimum time is up + if (state_timer_heater_1 == 0) { + // if change state set timer + if (state_heater_1 == 0) { + state_timer_heater_1 = MIN_STATE_TIME; + } + state_heater_1 = 1; + WRITE(HEATER_1_PIN, 1); + } + } else { + // turn OFF heather only if the minimum time is up + if (state_timer_heater_1 == 0) { + // if change state set timer + if (state_heater_1 == 1) { + state_timer_heater_1 = MIN_STATE_TIME; + } + state_heater_1 = 0; + WRITE(HEATER_1_PIN, 0); + } + } +#endif + +#if EXTRUDERS > 2 + // EXTRUDER 2 + soft_pwm_2 = soft_pwm[2]; + if (soft_pwm_2 > 0) { + // turn ON heather only if the minimum time is up + if (state_timer_heater_2 == 0) { + // if change state set timer + if (state_heater_2 == 0) { + state_timer_heater_2 = MIN_STATE_TIME; + } + state_heater_2 = 1; + WRITE(HEATER_2_PIN, 1); + } + } else { + // turn OFF heather only if the minimum time is up + if (state_timer_heater_2 == 0) { + // if change state set timer + if (state_heater_2 == 1) { + state_timer_heater_2 = MIN_STATE_TIME; + } + state_heater_2 = 0; + WRITE(HEATER_2_PIN, 0); + } + } +#endif + +#if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1 + // BED + soft_pwm_b = soft_pwm_bed; + if (soft_pwm_b > 0) { + // turn ON heather only if the minimum time is up + if (state_timer_heater_b == 0) { + // if change state set timer + if (state_heater_b == 0) { + state_timer_heater_b = MIN_STATE_TIME; + } + state_heater_b = 1; + WRITE(HEATER_BED_PIN, 1); + } + } else { + // turn OFF heather only if the minimum time is up + if (state_timer_heater_b == 0) { + // if change state set timer + if (state_heater_b == 1) { + state_timer_heater_b = MIN_STATE_TIME; + } + state_heater_b = 0; + WRITE(HEATER_BED_PIN, 0); + } + } +#endif + } // if (slow_pwm_count == 0) + + // EXTRUDER 0 + if (soft_pwm_0 < slow_pwm_count) { + // turn OFF heather only if the minimum time is up + if (state_timer_heater_0 == 0) { + // if change state set timer + if (state_heater_0 == 1) { + state_timer_heater_0 = MIN_STATE_TIME; + } + state_heater_0 = 0; + WRITE(HEATER_0_PIN, 0); +#ifdef HEATERS_PARALLEL + WRITE(HEATER_1_PIN, 0); +#endif + } + } + +#if EXTRUDERS > 1 + // EXTRUDER 1 + if (soft_pwm_1 < slow_pwm_count) { + // turn OFF heather only if the minimum time is up + if (state_timer_heater_1 == 0) { + // if change state set timer + if (state_heater_1 == 1) { + state_timer_heater_1 = MIN_STATE_TIME; + } + state_heater_1 = 0; + WRITE(HEATER_1_PIN, 0); + } + } +#endif + +#if EXTRUDERS > 2 + // EXTRUDER 2 + if (soft_pwm_2 < slow_pwm_count) { + // turn OFF heather only if the minimum time is up + if (state_timer_heater_2 == 0) { + // if change state set timer + if (state_heater_2 == 1) { + state_timer_heater_2 = MIN_STATE_TIME; + } + state_heater_2 = 0; + WRITE(HEATER_2_PIN, 0); + } + } +#endif + +#if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1 + // BED + if (soft_pwm_b < slow_pwm_count) { + // turn OFF heather only if the minimum time is up + if (state_timer_heater_b == 0) { + // if change state set timer + if (state_heater_b == 1) { + state_timer_heater_b = MIN_STATE_TIME; + } + state_heater_b = 0; + WRITE(HEATER_BED_PIN, 0); + } + } +#endif + +#ifdef FAN_SOFT_PWM + if (pwm_count == 0){ + soft_pwm_fan = fanSpeedSoftPwm / 2; + if (soft_pwm_fan > 0) WRITE(FAN_PIN,1); else WRITE(FAN_PIN,0); + } + if (soft_pwm_fan < pwm_count) WRITE(FAN_PIN,0); +#endif + + pwm_count += (1 << SOFT_PWM_SCALE); + pwm_count &= 0x7f; + + // increment slow_pwm_count only every 64 pwm_count circa 65.5ms + if ((pwm_count % 64) == 0) { + slow_pwm_count++; + slow_pwm_count &= 0x7f; + + // Extruder 0 + if (state_timer_heater_0 > 0) { + state_timer_heater_0--; + } + +#if EXTRUDERS > 1 + // Extruder 1 + if (state_timer_heater_1 > 0) + state_timer_heater_1--; +#endif + +#if EXTRUDERS > 2 + // Extruder 2 + if (state_timer_heater_2 > 0) + state_timer_heater_2--; +#endif + +#if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1 + // Bed + if (state_timer_heater_b > 0) + state_timer_heater_b--; +#endif + } //if ((pwm_count % 64) == 0) { + +#endif //ifndef SLOW_PWM_HEATERS + + switch(temp_state) { + case 0: // Prepare TEMP_0 + #if defined(TEMP_0_PIN) && (TEMP_0_PIN > -1) + #if TEMP_0_PIN > 7 + ADCSRB = 1< -1) + raw_temp_0_value += ADC; + #endif + #ifdef HEATER_0_USES_MAX6675 // TODO remove the blocking + raw_temp_0_value = read_max6675(); + #endif + temp_state = 2; + break; + case 2: // Prepare TEMP_BED + #if defined(TEMP_BED_PIN) && (TEMP_BED_PIN > -1) + #if TEMP_BED_PIN > 7 + ADCSRB = 1< -1) + raw_temp_bed_value += ADC; + #endif + temp_state = 4; + break; + case 4: // Prepare TEMP_1 + #if defined(TEMP_1_PIN) && (TEMP_1_PIN > -1) + #if TEMP_1_PIN > 7 + ADCSRB = 1< -1) + raw_temp_1_value += ADC; + #endif + temp_state = 6; + break; + case 6: // Prepare TEMP_2 + #if defined(TEMP_2_PIN) && (TEMP_2_PIN > -1) + #if TEMP_2_PIN > 7 + ADCSRB = 1< -1) + raw_temp_2_value += ADC; + #endif + temp_state = 8;//change so that Filament Width is also measured + + break; + case 8: //Prepare FILWIDTH + #if defined(FILWIDTH_PIN) && (FILWIDTH_PIN> -1) + #if FILWIDTH_PIN>7 + ADCSRB = 1< -1) + //raw_filwidth_value += ADC; //remove to use an IIR filter approach + if(ADC>102) //check that ADC is reading a voltage > 0.5 volts, otherwise don't take in the data. + { + raw_filwidth_value= raw_filwidth_value-(raw_filwidth_value>>7); //multipliy raw_filwidth_value by 127/128 + + raw_filwidth_value= raw_filwidth_value + ((unsigned long)ADC<<7); //add new ADC reading + } + #endif + temp_state = 0; + + temp_count++; + break; + + + case 10: //Startup, delay initial temp reading a tiny bit so the hardware can settle. + temp_state = 0; + break; +// default: +// SERIAL_ERROR_START; +// SERIAL_ERRORLNPGM("Temp measurement error!"); +// break; + } + + if(temp_count >= OVERSAMPLENR) // 10 * 16 * 1/(16000000/64/256) = 164ms. + { + if (!temp_meas_ready) //Only update the raw values if they have been read. Else we could be updating them during reading. + { + current_temperature_raw[0] = raw_temp_0_value; +#if EXTRUDERS > 1 + current_temperature_raw[1] = raw_temp_1_value; +#endif +#ifdef TEMP_SENSOR_1_AS_REDUNDANT + redundant_temperature_raw = raw_temp_1_value; +#endif +#if EXTRUDERS > 2 + current_temperature_raw[2] = raw_temp_2_value; +#endif + current_temperature_bed_raw = raw_temp_bed_value; + } + +//Add similar code for Filament Sensor - can be read any time since IIR filtering is used +#if defined(FILWIDTH_PIN) &&(FILWIDTH_PIN > -1) + current_raw_filwidth = raw_filwidth_value>>10; //need to divide to get to 0-16384 range since we used 1/128 IIR filter approach +#endif + + + temp_meas_ready = true; + temp_count = 0; + raw_temp_0_value = 0; + raw_temp_1_value = 0; + raw_temp_2_value = 0; + raw_temp_bed_value = 0; + +#if HEATER_0_RAW_LO_TEMP > HEATER_0_RAW_HI_TEMP + if(current_temperature_raw[0] <= maxttemp_raw[0]) { +#else + if(current_temperature_raw[0] >= maxttemp_raw[0]) { +#endif + max_temp_error(0); + } +#if HEATER_0_RAW_LO_TEMP > HEATER_0_RAW_HI_TEMP + if(current_temperature_raw[0] >= minttemp_raw[0]) { +#else + if(current_temperature_raw[0] <= minttemp_raw[0]) { +#endif + min_temp_error(0); + } +#if EXTRUDERS > 1 +#if HEATER_1_RAW_LO_TEMP > HEATER_1_RAW_HI_TEMP + if(current_temperature_raw[1] <= maxttemp_raw[1]) { +#else + if(current_temperature_raw[1] >= maxttemp_raw[1]) { +#endif + max_temp_error(1); + } +#if HEATER_1_RAW_LO_TEMP > HEATER_1_RAW_HI_TEMP + if(current_temperature_raw[1] >= minttemp_raw[1]) { +#else + if(current_temperature_raw[1] <= minttemp_raw[1]) { +#endif + min_temp_error(1); + } +#endif +#if EXTRUDERS > 2 +#if HEATER_2_RAW_LO_TEMP > HEATER_2_RAW_HI_TEMP + if(current_temperature_raw[2] <= maxttemp_raw[2]) { +#else + if(current_temperature_raw[2] >= maxttemp_raw[2]) { +#endif + max_temp_error(2); + } +#if HEATER_2_RAW_LO_TEMP > HEATER_2_RAW_HI_TEMP + if(current_temperature_raw[2] >= minttemp_raw[2]) { +#else + if(current_temperature_raw[2] <= minttemp_raw[2]) { +#endif + min_temp_error(2); + } +#endif + + /* No bed MINTEMP error? */ + + +#if defined(BED_MAXTEMP) && (TEMP_SENSOR_BED != 0) +# if HEATER_BED_RAW_LO_TEMP > HEATER_BED_RAW_HI_TEMP + if(current_temperature_bed_raw <= bed_maxttemp_raw) { +#else + if(current_temperature_bed_raw >= bed_maxttemp_raw) { +#endif + target_temperature_bed = 0; + bed_max_temp_error(); + } + } + +# if HEATER_BED_RAW_LO_TEMP > HEATER_BED_RAW_HI_TEMP + if(current_temperature_bed_raw >= bed_minttemp_raw) { +#else + if(current_temperature_bed_raw <= bed_minttemp_raw) { +#endif + bed_min_temp_error(); + } + +#endif + +#ifdef BABYSTEPPING + for(uint8_t axis=0;axis<3;axis++) + { + int curTodo=babystepsTodo[axis]; //get rid of volatile for performance + + if(curTodo>0) + { + babystep(axis,/*fwd*/true); + babystepsTodo[axis]--; //less to do next time + } + else + if(curTodo<0) + { + babystep(axis,/*fwd*/false); + babystepsTodo[axis]++; //less to do next time + } + } +#endif //BABYSTEPPING +} + +#ifdef PIDTEMP +// Apply the scale factors to the PID values + + +float scalePID_i(float i) +{ + return i*PID_dT; +} + +float unscalePID_i(float i) +{ + return i/PID_dT; +} + +float scalePID_d(float d) +{ + return d/PID_dT; +} + +float unscalePID_d(float d) +{ + return d*PID_dT; +} + +#endif //PIDTEMP + + diff --git a/Firmware/temperature.h b/Firmware/temperature.h index 0bb82e469..ea09f60b5 100644 --- a/Firmware/temperature.h +++ b/Firmware/temperature.h @@ -1,213 +1,215 @@ -/* - temperature.h - temperature controller - Part of Marlin - - Copyright (c) 2011 Erik van der Zalm - - Grbl is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Grbl is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grbl. If not, see . -*/ - -#ifndef temperature_h -#define temperature_h - -#include "Marlin.h" -#include "planner.h" -#ifdef PID_ADD_EXTRUSION_RATE - #include "stepper.h" -#endif - -// public functions -void tp_init(); //initialize the heating -void manage_heater(); //it is critical that this is called periodically. - -#ifdef FILAMENT_SENSOR -// For converting raw Filament Width to milimeters - float analog2widthFil(); - -// For converting raw Filament Width to an extrusion ratio - int widthFil_to_size_ratio(); -#endif - -// low level conversion routines -// do not use these routines and variables outside of temperature.cpp -extern int target_temperature[EXTRUDERS]; -extern float current_temperature[EXTRUDERS]; -#ifdef SHOW_TEMP_ADC_VALUES - extern int current_temperature_raw[EXTRUDERS]; - extern int current_temperature_bed_raw; -#endif -extern int target_temperature_bed; -extern float current_temperature_bed; -#ifdef TEMP_SENSOR_1_AS_REDUNDANT - extern float redundant_temperature; -#endif - -#if defined(CONTROLLERFAN_PIN) && CONTROLLERFAN_PIN > -1 - extern unsigned char soft_pwm_bed; -#endif - -#ifdef PIDTEMP - extern float Kp,Ki,Kd,Kc; - float scalePID_i(float i); - float scalePID_d(float d); - float unscalePID_i(float i); - float unscalePID_d(float d); - -#endif -#ifdef PIDTEMPBED - extern float bedKp,bedKi,bedKd; -#endif - - -#ifdef BABYSTEPPING - extern volatile int babystepsTodo[3]; -#endif - -inline void babystepsTodoZadd(int n) -{ - if (n != 0) { - CRITICAL_SECTION_START - babystepsTodo[Z_AXIS] += n; - CRITICAL_SECTION_END - } -} - -inline void babystepsTodoZsubtract(int n) -{ - if (n != 0) { - CRITICAL_SECTION_START - babystepsTodo[Z_AXIS] -= n; - CRITICAL_SECTION_END - } -} - -//high level conversion routines, for use outside of temperature.cpp -//inline so that there is no performance decrease. -//deg=degreeCelsius - -FORCE_INLINE float degHotend(uint8_t extruder) { - return current_temperature[extruder]; -}; - -#ifdef SHOW_TEMP_ADC_VALUES - FORCE_INLINE float rawHotendTemp(uint8_t extruder) { - return current_temperature_raw[extruder]; - }; - - FORCE_INLINE float rawBedTemp() { - return current_temperature_bed_raw; - }; -#endif - -FORCE_INLINE float degBed() { - return current_temperature_bed; -}; - -FORCE_INLINE float degTargetHotend(uint8_t extruder) { - return target_temperature[extruder]; -}; - -FORCE_INLINE float degTargetBed() { - return target_temperature_bed; -}; - -FORCE_INLINE void setTargetHotend(const float &celsius, uint8_t extruder) { - target_temperature[extruder] = celsius; -}; - -FORCE_INLINE void setTargetBed(const float &celsius) { - target_temperature_bed = celsius; -}; - -FORCE_INLINE bool isHeatingHotend(uint8_t extruder){ - return target_temperature[extruder] > current_temperature[extruder]; -}; - -FORCE_INLINE bool isHeatingBed() { - return target_temperature_bed > current_temperature_bed; -}; - -FORCE_INLINE bool isCoolingHotend(uint8_t extruder) { - return target_temperature[extruder] < current_temperature[extruder]; -}; - -FORCE_INLINE bool isCoolingBed() { - return target_temperature_bed < current_temperature_bed; -}; - -#define degHotend0() degHotend(0) -#define degTargetHotend0() degTargetHotend(0) -#define setTargetHotend0(_celsius) setTargetHotend((_celsius), 0) -#define isHeatingHotend0() isHeatingHotend(0) -#define isCoolingHotend0() isCoolingHotend(0) -#if EXTRUDERS > 1 -#define degHotend1() degHotend(1) -#define degTargetHotend1() degTargetHotend(1) -#define setTargetHotend1(_celsius) setTargetHotend((_celsius), 1) -#define isHeatingHotend1() isHeatingHotend(1) -#define isCoolingHotend1() isCoolingHotend(1) -#else -#define setTargetHotend1(_celsius) do{}while(0) -#endif -#if EXTRUDERS > 2 -#define degHotend2() degHotend(2) -#define degTargetHotend2() degTargetHotend(2) -#define setTargetHotend2(_celsius) setTargetHotend((_celsius), 2) -#define isHeatingHotend2() isHeatingHotend(2) -#define isCoolingHotend2() isCoolingHotend(2) -#else -#define setTargetHotend2(_celsius) do{}while(0) -#endif -#if EXTRUDERS > 3 -#error Invalid number of extruders -#endif - -#if (defined (TEMP_RUNAWAY_BED_HYSTERESIS) && TEMP_RUNAWAY_BED_TIMEOUT > 0) || (defined (TEMP_RUNAWAY_EXTRUDER_HYSTERESIS) && TEMP_RUNAWAY_EXTRUDER_TIMEOUT > 0) -static float temp_runaway_status[4]; -static float temp_runaway_target[4]; -static float temp_runaway_timer[4]; -static int temp_runaway_error_counter[4]; - -void temp_runaway_check(int _heater_id, float _target_temperature, float _current_temperature, float _output, bool _isbed); -void temp_runaway_stop(bool isPreheat); -#endif - -int getHeaterPower(int heater); -void disable_heater(); -void setWatch(); -void updatePID(); - - -FORCE_INLINE void autotempShutdown(){ - #ifdef AUTOTEMP - if(autotemp_enabled) - { - autotemp_enabled=false; - if(degTargetHotend(active_extruder)>autotemp_min) - setTargetHotend(0,active_extruder); - } - #endif -} - -void PID_autotune(float temp, int extruder, int ncycles); - -void setExtruderAutoFanState(int pin, bool state); -void checkExtruderAutoFans(); - +/* + temperature.h - temperature controller + Part of Marlin + + Copyright (c) 2011 Erik van der Zalm + + Grbl is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Grbl is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Grbl. If not, see . +*/ + +#ifndef temperature_h +#define temperature_h + +#include "Marlin.h" +#include "planner.h" +#ifdef PID_ADD_EXTRUSION_RATE + #include "stepper.h" +#endif + +// public functions +void tp_init(); //initialize the heating +void manage_heater(); //it is critical that this is called periodically. + +#ifdef FILAMENT_SENSOR +// For converting raw Filament Width to milimeters + float analog2widthFil(); + +// For converting raw Filament Width to an extrusion ratio + int widthFil_to_size_ratio(); +#endif + +// low level conversion routines +// do not use these routines and variables outside of temperature.cpp +extern int target_temperature[EXTRUDERS]; +extern float current_temperature[EXTRUDERS]; +#ifdef SHOW_TEMP_ADC_VALUES + extern int current_temperature_raw[EXTRUDERS]; + extern int current_temperature_bed_raw; +#endif +extern int target_temperature_bed; +extern float current_temperature_bed; +#ifdef TEMP_SENSOR_1_AS_REDUNDANT + extern float redundant_temperature; +#endif + +#if defined(CONTROLLERFAN_PIN) && CONTROLLERFAN_PIN > -1 + extern unsigned char soft_pwm_bed; +#endif + +#ifdef PIDTEMP + extern int pid_cycle, pid_number_of_cycles; + extern float Kp,Ki,Kd,Kc,_Kp,_Ki,_Kd; + extern bool pid_tuning_finished; + float scalePID_i(float i); + float scalePID_d(float d); + float unscalePID_i(float i); + float unscalePID_d(float d); + +#endif +#ifdef PIDTEMPBED + extern float bedKp,bedKi,bedKd; +#endif + + +#ifdef BABYSTEPPING + extern volatile int babystepsTodo[3]; +#endif + +inline void babystepsTodoZadd(int n) +{ + if (n != 0) { + CRITICAL_SECTION_START + babystepsTodo[Z_AXIS] += n; + CRITICAL_SECTION_END + } +} + +inline void babystepsTodoZsubtract(int n) +{ + if (n != 0) { + CRITICAL_SECTION_START + babystepsTodo[Z_AXIS] -= n; + CRITICAL_SECTION_END + } +} + +//high level conversion routines, for use outside of temperature.cpp +//inline so that there is no performance decrease. +//deg=degreeCelsius + +FORCE_INLINE float degHotend(uint8_t extruder) { + return current_temperature[extruder]; +}; + +#ifdef SHOW_TEMP_ADC_VALUES + FORCE_INLINE float rawHotendTemp(uint8_t extruder) { + return current_temperature_raw[extruder]; + }; + + FORCE_INLINE float rawBedTemp() { + return current_temperature_bed_raw; + }; +#endif + +FORCE_INLINE float degBed() { + return current_temperature_bed; +}; + +FORCE_INLINE float degTargetHotend(uint8_t extruder) { + return target_temperature[extruder]; +}; + +FORCE_INLINE float degTargetBed() { + return target_temperature_bed; +}; + +FORCE_INLINE void setTargetHotend(const float &celsius, uint8_t extruder) { + target_temperature[extruder] = celsius; +}; + +FORCE_INLINE void setTargetBed(const float &celsius) { + target_temperature_bed = celsius; +}; + +FORCE_INLINE bool isHeatingHotend(uint8_t extruder){ + return target_temperature[extruder] > current_temperature[extruder]; +}; + +FORCE_INLINE bool isHeatingBed() { + return target_temperature_bed > current_temperature_bed; +}; + +FORCE_INLINE bool isCoolingHotend(uint8_t extruder) { + return target_temperature[extruder] < current_temperature[extruder]; +}; + +FORCE_INLINE bool isCoolingBed() { + return target_temperature_bed < current_temperature_bed; +}; + +#define degHotend0() degHotend(0) +#define degTargetHotend0() degTargetHotend(0) +#define setTargetHotend0(_celsius) setTargetHotend((_celsius), 0) +#define isHeatingHotend0() isHeatingHotend(0) +#define isCoolingHotend0() isCoolingHotend(0) +#if EXTRUDERS > 1 +#define degHotend1() degHotend(1) +#define degTargetHotend1() degTargetHotend(1) +#define setTargetHotend1(_celsius) setTargetHotend((_celsius), 1) +#define isHeatingHotend1() isHeatingHotend(1) +#define isCoolingHotend1() isCoolingHotend(1) +#else +#define setTargetHotend1(_celsius) do{}while(0) +#endif +#if EXTRUDERS > 2 +#define degHotend2() degHotend(2) +#define degTargetHotend2() degTargetHotend(2) +#define setTargetHotend2(_celsius) setTargetHotend((_celsius), 2) +#define isHeatingHotend2() isHeatingHotend(2) +#define isCoolingHotend2() isCoolingHotend(2) +#else +#define setTargetHotend2(_celsius) do{}while(0) +#endif +#if EXTRUDERS > 3 +#error Invalid number of extruders +#endif + +#if (defined (TEMP_RUNAWAY_BED_HYSTERESIS) && TEMP_RUNAWAY_BED_TIMEOUT > 0) || (defined (TEMP_RUNAWAY_EXTRUDER_HYSTERESIS) && TEMP_RUNAWAY_EXTRUDER_TIMEOUT > 0) +static float temp_runaway_status[4]; +static float temp_runaway_target[4]; +static float temp_runaway_timer[4]; +static int temp_runaway_error_counter[4]; + +void temp_runaway_check(int _heater_id, float _target_temperature, float _current_temperature, float _output, bool _isbed); +void temp_runaway_stop(bool isPreheat, bool isBed); +#endif + +int getHeaterPower(int heater); +void disable_heater(); +void setWatch(); +void updatePID(); + + +FORCE_INLINE void autotempShutdown(){ + #ifdef AUTOTEMP + if(autotemp_enabled) + { + autotemp_enabled=false; + if(degTargetHotend(active_extruder)>autotemp_min) + setTargetHotend(0,active_extruder); + } + #endif +} + +void PID_autotune(float temp, int extruder, int ncycles); + +void setExtruderAutoFanState(int pin, bool state); +void checkExtruderAutoFans(); + void countFanSpeed(); void checkFanSpeed(); void fanSpeedError(unsigned char _fan); - -#endif - + +#endif + diff --git a/Firmware/thermistortables.h b/Firmware/thermistortables.h index ac1dea736..faa7e5667 100644 --- a/Firmware/thermistortables.h +++ b/Firmware/thermistortables.h @@ -1033,7 +1033,9 @@ const short temptable_12[][2] PROGMEM = { #define PtA 3.9083E-3 #define PtB -5.775E-7 +#define PtC -4.183E-12 #define PtRt(T,R0) ((R0)*(1.0+(PtA)*(T)+(PtB)*(T)*(T))) +#define PtRtNew(T,R0) ((R0)*(1.0+(PtA)*(T)+(PtB)*(T)*(T) + (T-100)*PtC*(T)*(T)*(T))) #define PtAdVal(T,R0,Rup) (short)(1024/(Rup/PtRt(T,R0)+1)) #define PtLine(T,R0,Rup) { PtAdVal(T,R0,Rup)*OVERSAMPLENR, T }, @@ -1061,6 +1063,124 @@ const short temptable_147[][2] PROGMEM = { PtLine(300,100,4700) }; #endif +// E3D Pt100 with 4k7 MiniRambo pullup, no Amp on the MiniRambo v1.3a +#if (THERMISTORHEATER_0 == 148) || (THERMISTORHEATER_1 == 148) || (THERMISTORHEATER_2 == 148) || (THERMISTORBED == 148) +const short temptable_148[][2] PROGMEM = { +// These values have been calculated and tested over many days. See https://docs.google.com/spreadsheets/d/1MJXa6feEe0mGVCT2TrBwLxVOMoLDkJlvfQ4JXhAdV_E +// Values that are missing from the 5C gap are missing due to resolution limits. +{19.00000 * OVERSAMPLENR, 0}, +{19.25000 * OVERSAMPLENR, 5}, +{19.50000 * OVERSAMPLENR, 10}, +{19.87500 * OVERSAMPLENR, 15}, +{20.25000 * OVERSAMPLENR, 20}, +{21.00000 * OVERSAMPLENR, 25}, +{21.75000 * OVERSAMPLENR, 35}, +{22.00000 * OVERSAMPLENR, 40}, +{23.00000 * OVERSAMPLENR, 50}, // 55C is more commonly used. +{23.75000 * OVERSAMPLENR, 60}, +{24.00000 * OVERSAMPLENR, 65}, +{24.06250 * OVERSAMPLENR, 70}, +{25.00000 * OVERSAMPLENR, 75}, +{25.50000 * OVERSAMPLENR, 85}, +{26.00000 * OVERSAMPLENR, 90}, +{26.93750 * OVERSAMPLENR,100}, +{27.00000 * OVERSAMPLENR,105}, +{27.37500 * OVERSAMPLENR,110}, +{28.00000 * OVERSAMPLENR,115}, +{29.00000 * OVERSAMPLENR,125}, +{29.25000 * OVERSAMPLENR,135}, +{30.00000 * OVERSAMPLENR,140}, +{35.50000 * OVERSAMPLENR,150}, +{31.00000 * OVERSAMPLENR,155}, +{32.00000 * OVERSAMPLENR,165}, +{32.18750 * OVERSAMPLENR,175}, +{33.00000 * OVERSAMPLENR,180}, +{33.62500 * OVERSAMPLENR,190}, +{34.00000 * OVERSAMPLENR,195}, +{35.00000 * OVERSAMPLENR,205}, +{35.50000 * OVERSAMPLENR,215}, +{36.00000 * OVERSAMPLENR,220}, +{36.75000 * OVERSAMPLENR,230}, +{37.00000 * OVERSAMPLENR,235}, +{37.75000 * OVERSAMPLENR,245}, +{38.00000 * OVERSAMPLENR,250}, +{38.12500 * OVERSAMPLENR,255}, +{39.00000 * OVERSAMPLENR,260}, +{40.00000 * OVERSAMPLENR,275}, +{40.25000 * OVERSAMPLENR,285}, +{41.00000 * OVERSAMPLENR,290}, +{41.25000 * OVERSAMPLENR,300}, +{42.00000 * OVERSAMPLENR,305}, +{43.00000 * OVERSAMPLENR,315}, +{43.25000 * OVERSAMPLENR,325}, +{44.00000 * OVERSAMPLENR,330}, +{44.18750 * OVERSAMPLENR,340}, +{45.00000 * OVERSAMPLENR,345}, +{45.25000 * OVERSAMPLENR,355}, +{46.00000 * OVERSAMPLENR,360}, +{46.62500 * OVERSAMPLENR,370}, +{47.00000 * OVERSAMPLENR,375}, +{47.25000 * OVERSAMPLENR,385}, +{48.00000 * OVERSAMPLENR,390}, +{48.75000 * OVERSAMPLENR,400}, +{49.00000 * OVERSAMPLENR,405}, +}; +#endif +#if (THERMISTORHEATER_0 == 247) || (THERMISTORHEATER_1 == 247) || (THERMISTORHEATER_2 == 247) || (THERMISTORBED == 247) // Pt100 with 4k7 MiniRambo pullup & PT100 Amplifier +const short temptable_247[][2] PROGMEM = { +// Calculated from Bob-the-Kuhn's PT100 calculator listed in https://github.com/MarlinFirmware/Marlin/issues/5543 +// and the table provided by E3D at http://wiki.e3d-online.com/wiki/E3D_PT100_Amplifier_Documentation#Output_Characteristics. +{ 0 * OVERSAMPLENR, 0}, +{241 * OVERSAMPLENR, 1}, +{249 * OVERSAMPLENR, 10}, +{259 * OVERSAMPLENR, 20}, +{267 * OVERSAMPLENR, 30}, +{275 * OVERSAMPLENR, 40}, +{283 * OVERSAMPLENR, 50}, +{291 * OVERSAMPLENR, 60}, +{299 * OVERSAMPLENR, 70}, +{307 * OVERSAMPLENR, 80}, +{315 * OVERSAMPLENR, 90}, +{323 * OVERSAMPLENR, 100}, +{331 * OVERSAMPLENR, 110}, +{340 * OVERSAMPLENR, 120}, +{348 * OVERSAMPLENR, 130}, +{354 * OVERSAMPLENR, 140}, +{362 * OVERSAMPLENR, 150}, +{370 * OVERSAMPLENR, 160}, +{378 * OVERSAMPLENR, 170}, +{386 * OVERSAMPLENR, 180}, +{394 * OVERSAMPLENR, 190}, +{402 * OVERSAMPLENR, 200}, +{410 * OVERSAMPLENR, 210}, +{418 * OVERSAMPLENR, 220}, +{426 * OVERSAMPLENR, 230}, +{432 * OVERSAMPLENR, 240}, +{440 * OVERSAMPLENR, 250}, +{448 * OVERSAMPLENR, 260}, +{454 * OVERSAMPLENR, 270}, +{462 * OVERSAMPLENR, 280}, +{469 * OVERSAMPLENR, 290}, +{475 * OVERSAMPLENR, 300}, +{483 * OVERSAMPLENR, 310}, +{491 * OVERSAMPLENR, 320}, +{499 * OVERSAMPLENR, 330}, +{505 * OVERSAMPLENR, 340}, +{513 * OVERSAMPLENR, 350}, +{519 * OVERSAMPLENR, 360}, +{527 * OVERSAMPLENR, 370}, +{533 * OVERSAMPLENR, 380}, +{541 * OVERSAMPLENR, 390}, +{549 * OVERSAMPLENR, 400}, +{616 * OVERSAMPLENR, 500}, +{682 * OVERSAMPLENR, 600}, +{741 * OVERSAMPLENR, 700}, +{801 * OVERSAMPLENR, 800}, +{856 * OVERSAMPLENR, 900}, +{910 * OVERSAMPLENR, 1000}, +{960 * OVERSAMPLENR, 1100}, +}; +#endif #if (THERMISTORHEATER_0 == 1010) || (THERMISTORHEATER_1 == 1010) || (THERMISTORHEATER_2 == 1010) || (THERMISTORBED == 1010) // Pt1000 with 1k0 pullup const short temptable_1010[][2] PROGMEM = { PtLine(0,1000,1000) diff --git a/Firmware/tmc2130.cpp b/Firmware/tmc2130.cpp new file mode 100644 index 000000000..8a150559e --- /dev/null +++ b/Firmware/tmc2130.cpp @@ -0,0 +1,364 @@ +#include "Marlin.h" + +#ifdef HAVE_TMC2130_DRIVERS + +#include "tmc2130.h" +#include + +uint32_t tmc2130_read(uint8_t chipselect, uint8_t address) +{ + uint32_t val32; + uint8_t val0; + uint8_t val1; + uint8_t val2; + uint8_t val3; + uint8_t val4; + //datagram1 - read request (address + dummy write) + SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE3)); + digitalWrite(chipselect,LOW); + SPI.transfer(address); + SPI.transfer(0); + SPI.transfer(0); + SPI.transfer(0); + SPI.transfer(0); + digitalWrite(chipselect, HIGH); + SPI.endTransaction(); + //datagram2 - response + SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE3)); + digitalWrite(chipselect,LOW); + val0 = SPI.transfer(0); + val1 = SPI.transfer(0); + val2 = SPI.transfer(0); + val3 = SPI.transfer(0); + val4 = SPI.transfer(0); + digitalWrite(chipselect, HIGH); + SPI.endTransaction(); +#ifdef TMC_DBG_READS + MYSERIAL.print("SPIRead 0x"); + MYSERIAL.print(address,HEX); + MYSERIAL.print(" Status:"); + MYSERIAL.print(val0 & 0b00000111,BIN); + MYSERIAL.print(" "); + MYSERIAL.print(val1,BIN); + MYSERIAL.print(" "); + MYSERIAL.print(val2,BIN); + MYSERIAL.print(" "); + MYSERIAL.print(val3,BIN); + MYSERIAL.print(" "); + MYSERIAL.print(val4,BIN); +#endif + val32 = (uint32_t)val1<<24 | (uint32_t)val2<<16 | (uint32_t)val3<<8 | (uint32_t)val4; +#ifdef TMC_DBG_READS + MYSERIAL.print(" 0x"); + MYSERIAL.println(val32,HEX); +#endif + return val32; +} + +void tmc2130_write(uint8_t chipselect, uint8_t address,uint8_t wval1,uint8_t wval2,uint8_t wval3,uint8_t wval4) +{ + uint32_t val32; + uint8_t val0; + uint8_t val1; + uint8_t val2; + uint8_t val3; + uint8_t val4; + //datagram1 - write + SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE3)); + digitalWrite(chipselect,LOW); + SPI.transfer(address+0x80); + SPI.transfer(wval1); + SPI.transfer(wval2); + SPI.transfer(wval3); + SPI.transfer(wval4); + digitalWrite(chipselect, HIGH); + SPI.endTransaction(); + //datagram2 - response + SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE3)); + digitalWrite(chipselect,LOW); + val0 = SPI.transfer(0); + val1 = SPI.transfer(0); + val2 = SPI.transfer(0); + val3 = SPI.transfer(0); + val4 = SPI.transfer(0); + digitalWrite(chipselect, HIGH); + SPI.endTransaction(); +#ifdef TMC_DBG_WRITE + MYSERIAL.print("WriteRead 0x"); + MYSERIAL.print(address,HEX); + MYSERIAL.print(" Status:"); + MYSERIAL.print(val0 & 0b00000111,BIN); + MYSERIAL.print(" "); + MYSERIAL.print(val1,BIN); + MYSERIAL.print(" "); + MYSERIAL.print(val2,BIN); + MYSERIAL.print(" "); + MYSERIAL.print(val3,BIN); + MYSERIAL.print(" "); + MYSERIAL.print(val4,BIN); + val32 = (uint32_t)val1<<24 | (uint32_t)val2<<16 | (uint32_t)val3<<8 | (uint32_t)val4; + MYSERIAL.print(" 0x"); + MYSERIAL.println(val32,HEX); +#endif //TMC_DBG_READS +} + +uint8_t tmc2130_read8(uint8_t chipselect, uint8_t address) +{ + //datagram1 - write + SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE3)); + digitalWrite(chipselect,LOW); + SPI.transfer(address); + SPI.transfer(0x00); + SPI.transfer(0x00); + SPI.transfer(0x00); + SPI.transfer(0x00); + digitalWrite(chipselect, HIGH); + SPI.endTransaction(); + uint8_t val0; + //datagram2 - response + SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE3)); + digitalWrite(chipselect,LOW); + val0 = SPI.transfer(0); + digitalWrite(chipselect, HIGH); + SPI.endTransaction(); + return val0; +} + +uint32_t tmc2130_readRegister(uint8_t chipselect, uint8_t address) +{ + //datagram1 - write + SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE3)); + digitalWrite(chipselect,LOW); + SPI.transfer(address); + SPI.transfer(0x00); + SPI.transfer(0x00); + SPI.transfer(0x00); + SPI.transfer(0x00); + digitalWrite(chipselect, HIGH); + SPI.endTransaction(); + uint32_t val0; + //datagram2 - response + SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE3)); + digitalWrite(chipselect,LOW); + SPI.transfer(0); // ignore status bits + val0 = SPI.transfer(0); // MSB + val0 = (val0 << 8) | SPI.transfer(0); + val0 = (val0 << 8) | SPI.transfer(0); + val0 = (val0 << 8) | SPI.transfer(0); //LSB + digitalWrite(chipselect, HIGH); + SPI.endTransaction(); + return val0; +} + +uint16_t tmc2130_readSG(uint8_t chipselect) +{ + uint8_t address = 0x6F; + uint32_t registerValue = tmc2130_readRegister(chipselect, address); + uint16_t val0 = registerValue & 0x3ff; + return val0; +} + +uint16_t tmc2130_readTStep(uint8_t chipselect) +{ + uint8_t address = 0x12; + uint32_t registerValue = tmc2130_readRegister(chipselect, address); + uint16_t val0 = 0; + if(registerValue & 0x000f0000) + val0 = 0xffff; + else + val0 = registerValue & 0xffff; + return val0; +} + +void tmc2130_chopconf(uint8_t cs, bool extrapolate256 = 0, uint16_t microstep_resolution = 16) +{ + uint8_t mres=0b0100; + if(microstep_resolution == 256) mres = 0b0000; + if(microstep_resolution == 128) mres = 0b0001; + if(microstep_resolution == 64) mres = 0b0010; + if(microstep_resolution == 32) mres = 0b0011; + if(microstep_resolution == 16) mres = 0b0100; + if(microstep_resolution == 8) mres = 0b0101; + if(microstep_resolution == 4) mres = 0b0110; + if(microstep_resolution == 2) mres = 0b0111; + if(microstep_resolution == 1) mres = 0b1000; + mres |= extrapolate256 << 4; //bit28 intpol + //tmc2130_write(cs,0x6C,mres,0x01,0x00,0xD3); + tmc2130_write(cs,0x6C,mres,0x01,0x00,0xC3); +} + +void tmc2130_PWMconf(uint8_t cs, uint8_t PWMautoScale = PWM_AUTOSCALE, uint8_t PWMfreq = PWM_FREQ, uint8_t PWMgrad = PWM_GRAD, uint8_t PWMampl = PWM_AMPL) +{ + tmc2130_write(cs,0x70,0x00,(PWMautoScale+PWMfreq),PWMgrad,PWMampl); // TMC LJ -> For better readability changed to 0x00 and added PWMautoScale and PWMfreq +} + +void tmc2130_PWMthreshold(uint8_t cs) +{ + tmc2130_write(cs,0x13,0x00,0x00,0x00,0x00); // TMC LJ -> Adds possibility to swtich from stealthChop to spreadCycle automatically +} + + +uint8_t st_didLastHomingStall() +{ + uint8_t returnValue = sg_lastHomingStalled; + sg_lastHomingStalled = false; + return returnValue; +} + +void tmc2130_disable_motor(uint8_t driver) +{ + uint8_t cs[4] = { X_TMC2130_CS, Y_TMC2130_CS, Z_TMC2130_CS, E0_TMC2130_CS }; + tmc2130_write(cs[driver],0x6C,0,01,0,0); +} + +void tmc2130_check_overtemp() +{ + const static char TMC_OVERTEMP_MSG[] PROGMEM = "TMC DRIVER OVERTEMP "; + uint8_t cs[4] = { X_TMC2130_CS, Y_TMC2130_CS, Z_TMC2130_CS, E0_TMC2130_CS }; + static uint32_t checktime = 0; + //drivers_disabled[0] = 1; //TEST + if( millis() - checktime > 1000 ) + { + for(int i=0;i<4;i++) + { + uint32_t drv_status = tmc2130_read(cs[i], 0x6F); //0x6F DRV_STATUS + if (drv_status & ((uint32_t)1<<26)) + { // BIT 26 - over temp prewarning ~120C (+-20C) + SERIAL_ERRORRPGM(TMC_OVERTEMP_MSG); + SERIAL_ECHOLN(i); + for(int x=0; x<4;x++) tmc2130_disable_motor(x); + kill(TMC_OVERTEMP_MSG); + } + } + checktime = millis(); + } +} + +void tmc2130_init() +{ + uint8_t cs[4] = { X_TMC2130_CS, Y_TMC2130_CS, Z_TMC2130_CS, E0_TMC2130_CS }; + // uint8_t current[4] = { 31, 31, 31, 31 }; + // uint8_t current_h[4] = { 12, 12, 12, 12 }; + // uint8_t current_r[4] = { 24, 24, 24, 24 }; + // uint8_t current_r[4] = { 32, 32, 32, 32 }; + // uint8_t current_h[4] = { 14, 14, 14, 14 }; + uint8_t current_h[4] = { 2, 2, 2, 4 }; + uint8_t current_r[4] = { 6, 6, 8, 8 }; + WRITE(X_TMC2130_CS, HIGH); + WRITE(Y_TMC2130_CS, HIGH); + WRITE(Z_TMC2130_CS, HIGH); + WRITE(E0_TMC2130_CS, HIGH); + SET_OUTPUT(X_TMC2130_CS); + SET_OUTPUT(Y_TMC2130_CS); + SET_OUTPUT(Z_TMC2130_CS); + SET_OUTPUT(E0_TMC2130_CS); + SPI.begin(); +/* for(int i=0;i<4;i++) + { + //tmc2130_write(cs[i],0x6C,0b10100,01,00,0xC5); + tmc2130_chopconf(cs[i],1,16); + tmc2130_write(cs[i],0x10,0,15,current_h[i],current_r[i]); //0x10 IHOLD_IRUN + //tmc2130_write(cs[i],0x0,0,0,0,0x05); //address=0x0 GCONF EXT VREF + tmc2130_write(cs[i],0x0,0,0,0,0x05); //address=0x0 GCONF EXT VREF - activate stealthChop + //tmc2130_write(cs[i],0x11,0,0,0,0xA); + + // Uncomment lines below to use a different configuration (pwm_autoscale = 0) for XY axes + if(i==0 || i==1) + tmc2130_PWMconf(cs[i],PWM_AUTOSCALE_XY,PWM_FREQ_XY,PWM_GRAD_XY,PWM_AMPL_XY); //address=0x70 PWM_CONF //reset default=0x00050480 + else + tmc2130_PWMconf(cs[i]); //address=0x70 PWM_CONF //reset default=0x00050480 + tmc2130_PWMthreshold(cs[i]); + } +*/ +#ifdef MK3_TEST1 + for (int i=0;i<4;i++) + { + tmc2130_write(cs[i],0x0,0,0,0,0x00); //address=0x0 GCONF - bit 2 activate stealthChop + tmc2130_write(cs[i],0x10,0,15,current_r[i],current_h[i]); //0x10 IHOLD_IRUN + tmc2130_chopconf(cs[i],0,16); + } +#else //MK3_TEST1 + for (int i=0;i<3;i++) + { + tmc2130_write(cs[i],0x0,0,0,0,0x04); //address=0x0 GCONF - bit 2 activate stealthChop + tmc2130_write(cs[i],0x10,0,15,current_r[i],current_h[i]); //0x10 IHOLD_IRUN + tmc2130_write(cs[i],0x11,0,0,0,0); + tmc2130_PWMconf(cs[i]); //address=0x70 PWM_CONF //reset default=0x00050480 + // tmc2130_PWMthreshold(cs[i]); + tmc2130_chopconf(cs[i],1,16); + } + for (int i=3;i<4;i++) + { + tmc2130_write(cs[i],0x0,0,0,0,0x00); //address=0x0 GCONF - bit 2 activate stealthChop + tmc2130_write(cs[i],0x10,0,15,current_r[i],current_h[i]); //0x10 IHOLD_IRUN + tmc2130_write(cs[i],0x11,0,0,0,0); + tmc2130_chopconf(cs[i],1,16); + } +#endif //MK3_TEST1 +} + +void tmc2130_st_synchronize() +{ + uint8_t delay = 0; + if(sg_homing_axis == X_AXIS || sg_homing_axis == Y_AXIS) + { + uint8_t axis; + if(sg_homing_axis == X_AXIS) + axis = X_TMC2130_CS; + else + axis = Y_TMC2130_CS; + uint16_t tstep = tmc2130_readTStep(axis); + // SERIAL_PROTOCOLLN(tstep); + if(tstep < TCOOLTHRS) + { + if(delay < 255) // wait for a few tens microsteps until stallGuard is used //todo: read out microsteps directly, instead of delay counter + delay++; + else + { + uint16_t sg = tmc2130_readSG(axis); + if(sg==0) + { + sg_axis_stalled[sg_homing_axis] = true; + sg_lastHomingStalled = true; + } + else + sg_axis_stalled[sg_homing_axis] = false; +// SERIAL_PROTOCOLLN(sg); + } + } + else + { + sg_axis_stalled[sg_homing_axis] = false; + delay = 0; + } + } + else + { + sg_axis_stalled[X_AXIS] = false; + sg_axis_stalled[Y_AXIS] = false; + } +} + +void tmc2130_st_home_enter(uint8_t axis) +{ + sg_homing_axis = axis; +// Configuration to spreadCycle +// tmc2130_write((axis == X_AXIS)? X_TMC2130_CS : Y_TMC2130_CS,0x0,0,0,0,0x01); + tmc2130_write((axis == X_AXIS)? X_TMC2130_CS : Y_TMC2130_CS,0x0,0,0,0,0x00); + tmc2130_write((axis == X_AXIS)? X_TMC2130_CS : Y_TMC2130_CS,0x6D,0,(axis == X_AXIS)?SG_THRESHOLD_X:SG_THRESHOLD_Y,0,0); + tmc2130_write((axis == X_AXIS)? X_TMC2130_CS : Y_TMC2130_CS,0x14,0,0,0,TCOOLTHRS); +} + +void tmc2130_st_home_exit() +{ + if ((sg_homing_axis == X_AXIS) || (sg_homing_axis == X_AXIS)) + { + // Configuration back to stealthChop + tmc2130_write((sg_homing_axis == X_AXIS)? X_TMC2130_CS : Y_TMC2130_CS, 0x0, 0, 0, 0, 0x04); + sg_homing_axis = 0xff; + sg_axis_stalled[X_AXIS] = false; + sg_axis_stalled[Y_AXIS] = false; + } +} + +#endif //HAVE_TMC2130_DRIVERS diff --git a/Firmware/tmc2130.h b/Firmware/tmc2130.h new file mode 100644 index 000000000..3d4f1a100 --- /dev/null +++ b/Firmware/tmc2130.h @@ -0,0 +1,26 @@ +#ifndef TMC2130_H +#define TMC2130_H + +static uint8_t sg_homing_axis = 0xFF; +static uint8_t sg_axis_stalled[2] = {0, 0}; +static uint8_t sg_lastHomingStalled = false; + +void tmc2130_check_overtemp(); + +void tmc2130_write(uint8_t chipselect, uint8_t address,uint8_t wval1,uint8_t wval2,uint8_t wval3,uint8_t wval4); +uint8_t tmc2130_read8(uint8_t chipselect, uint8_t address); +uint16_t tmc2130_readSG(uint8_t chipselect); +uint16_t tmc2130_readTStep(uint8_t chipselect); +void tmc2130_PWMconf(uint8_t cs, uint8_t PWMgrad, uint8_t PWMampl); + +uint8_t st_didLastHomingStall(); + +void tmc2130_st_synchronize(); + +void tmc2130_st_home_enter(uint8_t axis); + +void tmc2130_st_home_exit(); + +void tmc2130_init(); + +#endif TMC2130_H \ No newline at end of file diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp index 336f06bef..6adddd502 100644 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -97,6 +97,10 @@ int8_t SDscrool = 0; int8_t SilentModeMenu = 0; +#ifdef SNMM +uint8_t snmm_extruder = 0; +#endif + int lcd_commands_type=LCD_COMMAND_IDLE; int lcd_commands_step=0; bool isPrintPaused = false; @@ -107,9 +111,12 @@ int farm_status = 0; unsigned long allert_timer = millis(); bool printer_connected = true; +unsigned long display_time; //just timer for showing pid finished message on lcd; +float pid_temp = DEFAULT_PID_TEMP; bool long_press_active = false; long long_press_timer = millis(); +long button_blanking_time = millis(); bool button_pressed = false; bool menuExiting = false; @@ -504,22 +511,100 @@ static void lcd_status_screen() lcd.setCursor(0, 3); lcd_printPGM(MSG_PRINTER_DISCONNECTED); } - - lcd.setCursor(0, 3); - lcd_implementation_print(pat9125_x); - lcd.setCursor(10, 3); - lcd_implementation_print(pat9125_y); + + lcd.setCursor(0, 3); + lcd_implementation_print(pat9125_x); + lcd.setCursor(10, 3); + lcd_implementation_print(pat9125_y); } #ifdef ULTIPANEL void lcd_commands() -{ +{ + char cmd1[25]; + if (lcd_commands_type == LCD_COMMAND_LONG_PAUSE) + { + if(lcd_commands_step == 0) { + card.pauseSDPrint(); + lcd_setstatuspgm(MSG_FINISHING_MOVEMENTS); + lcdDrawUpdate = 3; + lcd_commands_step = 1; + } + if (lcd_commands_step == 1 && !blocks_queued()) { + lcd_setstatuspgm(MSG_PRINT_PAUSED); + isPrintPaused = true; + long_pause(); + lcd_commands_type = 0; + lcd_commands_step = 0; + } + + } + + if (lcd_commands_type == LCD_COMMAND_LONG_PAUSE_RESUME) { + char cmd1[30]; + if (lcd_commands_step == 0) { + + lcdDrawUpdate = 3; + lcd_commands_step = 4; + } + if (lcd_commands_step == 1 && !blocks_queued()) { //recover feedmultiply + + sprintf_P(cmd1, PSTR("M220 S%d"), saved_feedmultiply); + enquecommand(cmd1); + isPrintPaused = false; + pause_time += (millis() - start_pause_print); //accumulate time when print is paused for correct statistics calculation + card.startFileprint(); + lcd_commands_step = 0; + lcd_commands_type = 0; + } + if (lcd_commands_step == 2 && !blocks_queued()) { //turn on fan, move Z and unretract + + sprintf_P(cmd1, PSTR("M106 S%d"), fanSpeedBckp); + enquecommand(cmd1); + strcpy(cmd1, "G1 Z"); + strcat(cmd1, ftostr32(pause_lastpos[Z_AXIS])); + enquecommand(cmd1); + if (axis_relative_modes[3] == true) enquecommand_P(PSTR("M83")); // set extruder to relative mode. + else enquecommand_P(PSTR("M82")); // set extruder to absolute mode + enquecommand_P(PSTR("G1 E" STRINGIFY(DEFAULT_RETRACTION))); //unretract + enquecommand_P(PSTR("G90")); //absolute positioning + lcd_commands_step = 1; + } + if (lcd_commands_step == 3 && !blocks_queued()) { //wait for nozzle to reach target temp + + strcpy(cmd1, "M109 S"); + strcat(cmd1, ftostr3(HotendTempBckp)); + enquecommand(cmd1); + lcd_commands_step = 2; + } + if (lcd_commands_step == 4 && !blocks_queued()) { //set temperature back and move xy + + strcpy(cmd1, "M104 S"); + strcat(cmd1, ftostr3(HotendTempBckp)); + enquecommand(cmd1); + + strcpy(cmd1, "G1 X"); + strcat(cmd1, ftostr32(pause_lastpos[X_AXIS])); + strcat(cmd1, " Y"); + strcat(cmd1, ftostr32(pause_lastpos[Y_AXIS])); + enquecommand(cmd1); + + lcd_setstatuspgm(MSG_RESUMING_PRINT); + lcd_commands_step = 3; + } + } + if (lcd_commands_type == LCD_COMMAND_STOP_PRINT) /// stop print { + uint8_t stopped_extruder; - if (lcd_commands_step == 0) { lcd_commands_step = 6; custom_message = true; } + if (lcd_commands_step == 0) + { + lcd_commands_step = 6; + custom_message = true; + } if (lcd_commands_step == 1 && !blocks_queued()) { @@ -533,9 +618,8 @@ void lcd_commands() if (lcd_commands_step == 2 && !blocks_queued()) { setTargetBed(0); - setTargetHotend(0, 0); - setTargetHotend(0, 1); - setTargetHotend(0, 2); + enquecommand_P(PSTR("M104 S0")); //set hotend temp to 0 + manage_heater(); lcd_setstatuspgm(WELCOME_MSG); cancel_heatup = false; @@ -545,9 +629,6 @@ void lcd_commands() { // M84: Disable steppers. enquecommand_P(PSTR("M84")); -#ifdef SNMM - enquecommand_P(PSTR("PRUSA ResF")); //resets flag at the end of the print (used for SNMM) -#endif autotempShutdown(); lcd_commands_step = 2; } @@ -565,7 +646,7 @@ void lcd_commands() #endif lcd_ignore_click(false); #ifdef SNMM - lcd_commands_step = 7; + lcd_commands_step = 8; #else lcd_commands_step = 3; #endif @@ -586,7 +667,7 @@ void lcd_commands() cancel_heatup = true; setTargetBed(0); #ifndef SNMM - setTargetHotend(0, 0); //to heating when changing filament for multicolor + setTargetHotend(0, 0); //heating when changing filament for multicolor setTargetHotend(0, 1); setTargetHotend(0, 2); #endif @@ -596,64 +677,17 @@ void lcd_commands() lcd_commands_step = 5; } if (lcd_commands_step == 7 && !blocks_queued()) { - /*ramming(); - st_synchronize(); - change_extr(0);*/ - st_synchronize(); - enquecommand_P(PSTR("M907 E700")); //set extruder current higher - enquecommand_P(PSTR("M203 E50")); - st_synchronize(); - if (current_temperature[0] < 230) { - // PLA - - //enquecommand_P(PSTR("G1 E-8 F2100.000000")); - //enquecommand_P(PSTR("G1 E8 F2100.000000")); - enquecommand_P(PSTR("G1 E5.4 F2800.000000")); - enquecommand_P(PSTR("G1 E3.2 F3000.000000")); - enquecommand_P(PSTR("G1 E3 F3400.000000")); - enquecommand_P(PSTR("M203 E80")); - st_synchronize(); - enquecommand_P(PSTR("G1 E-82 F9500.000000")); - enquecommand_P(PSTR("M203 E50")); - enquecommand_P(PSTR("G1 E-20 F1200.000000")); - enquecommand_P(PSTR("G1 E5 F400.000000")); - enquecommand_P(PSTR("G1 E5 F600.000000")); - st_synchronize(); - enquecommand_P(PSTR("G1 E-10 F600.000000")); - enquecommand_P(PSTR("G1 E+10 F600.000000")); - enquecommand_P(PSTR("G1 E-10 F800.000000")); - enquecommand_P(PSTR("G1 E+10 F800.000000")); - enquecommand_P(PSTR("G1 E-10 F800.000000")); - st_synchronize(); - }else { - // ABS - - //enquecommand_P(PSTR("G1 E-8 F2100.000000")); - //enquecommand_P(PSTR("G1 E8 F2100.000000")); - enquecommand_P(PSTR("G1 E3.1 F2000.000000")); - enquecommand_P(PSTR("G1 E3.1 F2500.000000")); - enquecommand_P(PSTR("G1 E4 F3000.000000")); - st_synchronize(); - enquecommand_P(PSTR("G4 P4700")); - enquecommand_P(PSTR("M203 E80")); - enquecommand_P(PSTR("G1 E-92 F9900.000000")); - enquecommand_P(PSTR("M203 E50")); - enquecommand_P(PSTR("G1 E-5 F800.000000")); - enquecommand_P(PSTR("G1 E5 F400.000000")); - st_synchronize(); - enquecommand_P(PSTR("G1 E-5 F600.000000")); - enquecommand_P(PSTR("G1 E5 F600.000000")); - enquecommand_P(PSTR("G1 E-5 F600.000000")); - enquecommand_P(PSTR("G1 E5 F600.000000")); - enquecommand_P(PSTR("G1 E5 F600.000000")); - st_synchronize(); + switch(snmm_stop_print_menu()) { + case 0: enquecommand_P(PSTR("M702")); break;//all + case 1: enquecommand_P(PSTR("M702 U")); break; //used + case 2: enquecommand_P(PSTR("M702 C")); break; //current + default: enquecommand_P(PSTR("M702")); break; } - enquecommand_P(PSTR("T0")); - enquecommand_P(PSTR("M907 E550")); //set extruder current to 500 - //digipot_init(); - lcd_commands_step = 3; } + if (lcd_commands_step == 8 && !blocks_queued()) { //step 8 is here for delay (going to next step after execution of all gcodes from step 4) + lcd_commands_step = 7; + } } if (lcd_commands_type == 3) @@ -703,6 +737,47 @@ void lcd_commands() } } + if (lcd_commands_type == LCD_COMMAND_PID_EXTRUDER) { + char cmd1[30]; + + if (lcd_commands_step == 0) { + custom_message_type = 3; + custom_message_state = 1; + custom_message = true; + lcdDrawUpdate = 3; + lcd_commands_step = 3; + } + if (lcd_commands_step == 3 && !blocks_queued()) { //PID calibration + strcpy(cmd1, "M303 E0 S"); + strcat(cmd1, ftostr3(pid_temp)); + enquecommand(cmd1); + lcd_setstatuspgm(MSG_PID_RUNNING); + lcd_commands_step = 2; + } + if (lcd_commands_step == 2 && pid_tuning_finished) { //saving to eeprom + pid_tuning_finished = false; + custom_message_state = 0; + lcd_setstatuspgm(MSG_PID_FINISHED); + strcpy(cmd1, "M301 P"); + strcat(cmd1, ftostr32(_Kp)); + strcat(cmd1, " I"); + strcat(cmd1, ftostr32(_Ki)); + strcat(cmd1, " D"); + strcat(cmd1, ftostr32(_Kd)); + enquecommand(cmd1); + enquecommand_P(PSTR("M500")); + display_time = millis(); + lcd_commands_step = 1; + } + if ((lcd_commands_step == 1) && ((millis()- display_time)>2000)) { //calibration finished message + lcd_setstatuspgm(WELCOME_MSG); + custom_message_type = 0; + custom_message = false; + pid_temp = DEFAULT_PID_TEMP; + lcd_commands_step = 0; + lcd_commands_type = 0; + } + } } @@ -717,16 +792,16 @@ static void lcd_return_to_status() { lcd_goto_menu(lcd_status_screen, 0, false); } + static void lcd_sdcard_pause() { - card.pauseSDPrint(); - isPrintPaused = true; - lcdDrawUpdate = 3; + lcd_return_to_status(); + lcd_commands_type = LCD_COMMAND_LONG_PAUSE; + } static void lcd_sdcard_resume() { - card.startFileprint(); - isPrintPaused = false; - lcdDrawUpdate = 3; + lcd_return_to_status(); + lcd_commands_type = LCD_COMMAND_LONG_PAUSE_RESUME; } float move_menu_scale; @@ -870,7 +945,10 @@ static void lcd_support_menu() MENU_ITEM(back, PSTR("FlashAir IP Addr:"), lcd_main_menu); MENU_ITEM(back_RAM, menuData.supportMenu.ip_str, lcd_main_menu); } - + #ifndef MK1BP + MENU_ITEM(back, PSTR("------------"), lcd_main_menu); + MENU_ITEM(function, PSTR("XYZ cal. details"), lcd_service_mode_show_result); + #endif //MK1BP END_MENU(); } @@ -913,8 +991,11 @@ void lcd_wait_interact() { lcd_implementation_clear(); lcd.setCursor(0, 1); - +#ifdef SNMM + lcd_printPGM(MSG_PREPARE_FILAMENT); +#else lcd_printPGM(MSG_INSERT_FILAMENT); +#endif lcd.setCursor(0, 2); lcd_printPGM(MSG_PRESS); @@ -972,7 +1053,6 @@ void lcd_loading_filament() { lcd.setCursor(0, 2); lcd_printPGM(MSG_PLEASE_WAIT); - for (int i = 0; i < 20; i++) { lcd.setCursor(i, 3); @@ -980,7 +1060,11 @@ void lcd_loading_filament() { for (int j = 0; j < 10 ; j++) { manage_heater(); manage_inactivity(true); - delay(110); +#ifdef SNMM + delay(153); +#else + delay(137); +#endif } @@ -1269,6 +1353,57 @@ static void lcd_move_e() } } +void lcd_service_mode_show_result() { + lcd_set_custom_characters_degree(); + count_xyz_details(); + lcd_update_enable(false); + lcd_implementation_clear(); + lcd_printPGM(PSTR("Y distance from min:")); + lcd_print_at_PGM(0, 1, PSTR("Left:")); + lcd_print_at_PGM(0, 2, PSTR("Center:")); + lcd_print_at_PGM(0, 3, PSTR("Right:")); + for (int i = 0; i < 3; i++) { + if(distance_from_min[i] < 200) { + lcd_print_at_PGM(8, i + 1, PSTR("")); + lcd.print(distance_from_min[i]); + lcd_print_at_PGM((distance_from_min[i] < 0) ? 14 : 13, i + 1, PSTR("mm")); + } else lcd_print_at_PGM(8, i + 1, PSTR("N/A")); + } + delay_keep_alive(500); + while (!lcd_clicked()) { + delay_keep_alive(100); + } + delay_keep_alive(500); + lcd_implementation_clear(); + + + lcd_printPGM(PSTR("Measured skew: ")); + if (angleDiff < 100) { + lcd.print(angleDiff * 180 / M_PI); + lcd.print(LCD_STR_DEGREE); + }else lcd_print_at_PGM(15, 0, PSTR("N/A")); + lcd_print_at_PGM(0, 1, PSTR("--------------------")); + lcd_print_at_PGM(0, 2, PSTR("Slight skew:")); + lcd_print_at_PGM(15, 2, PSTR("")); + lcd.print(bed_skew_angle_mild * 180 / M_PI); + lcd.print(LCD_STR_DEGREE); + lcd_print_at_PGM(0, 3, PSTR("Severe skew:")); + lcd_print_at_PGM(15, 3, PSTR("")); + lcd.print(bed_skew_angle_extreme * 180 / M_PI); + lcd.print(LCD_STR_DEGREE); + delay_keep_alive(500); + while (!lcd_clicked()) { + delay_keep_alive(100); + } + delay_keep_alive(500); + lcd_set_custom_characters_arrows(); + lcd_return_to_status(); + lcd_update_enable(true); + lcd_update(2); +} + + + // Save a single axis babystep value. void EEPROM_save_B(int pos, int* value) @@ -1439,6 +1574,25 @@ static void lcd_adjust_bed() END_MENU(); } +void pid_extruder() { + + lcd_implementation_clear(); + lcd.setCursor(1, 0); + lcd_printPGM(MSG_SET_TEMPERATURE); + pid_temp += int(encoderPosition); + if (pid_temp > HEATER_0_MAXTEMP) pid_temp = HEATER_0_MAXTEMP; + if (pid_temp < HEATER_0_MINTEMP) pid_temp = HEATER_0_MINTEMP; + encoderPosition = 0; + lcd.setCursor(1, 2); + lcd.print(ftostr3(pid_temp)); + if (lcd_clicked()) { + lcd_commands_type = LCD_COMMAND_PID_EXTRUDER; + lcd_return_to_status(); + lcd_update(2); + } + +} + void lcd_adjust_z() { int enc_dif = 0; int cursor_pos = 1; @@ -2280,7 +2434,7 @@ static void lcd_language_menu() void lcd_mesh_bedleveling() { - + mesh_bed_run_from_menu = true; enquecommand_P(PSTR("G80")); lcd_return_to_status(); } @@ -2297,6 +2451,32 @@ void lcd_mesh_calibration_z() lcd_return_to_status(); } +void lcd_pinda_calibration_menu() +{ + START_MENU(); + MENU_ITEM(back, MSG_MENU_CALIBRATION, lcd_calibration_menu); + MENU_ITEM(submenu, MSG_CALIBRATE_PINDA, lcd_calibrate_pinda); + if (temp_cal_active == false) { + MENU_ITEM(function, MSG_TEMP_CALIBRATION_OFF, lcd_temp_calibration_set); + } + else { + MENU_ITEM(function, MSG_TEMP_CALIBRATION_ON, lcd_temp_calibration_set); + } + END_MENU(); +} + +void lcd_temp_calibration_set() { + temp_cal_active = !temp_cal_active; + eeprom_update_byte((unsigned char *)EEPROM_TEMP_CAL_ACTIVE, temp_cal_active); + digipot_init(); + lcd_goto_menu(lcd_pinda_calibration_menu, 2); +} + +void lcd_calibrate_pinda() { + enquecommand_P(PSTR("G76")); + lcd_return_to_status(); +} + #ifndef SNMM /*void lcd_calibrate_extruder() { @@ -2451,25 +2631,32 @@ static void lcd_calibration_menu() if (!isPrintPaused) { MENU_ITEM(function, MSG_SELFTEST, lcd_selftest); -#ifndef MESH_BED_LEVELING +#ifdef MK1BP // MK1 // "Calibrate Z" MENU_ITEM(gcode, MSG_HOMEYZ, PSTR("G28 Z")); -#else +#else //MK1BP // MK2 MENU_ITEM(function, MSG_CALIBRATE_BED, lcd_mesh_calibration); // "Calibrate Z" with storing the reference values to EEPROM. MENU_ITEM(submenu, MSG_HOMEYZ, lcd_mesh_calibration_z); + #ifndef SNMM //MENU_ITEM(function, MSG_CALIBRATE_E, lcd_calibrate_extruder); #endif // "Mesh Bed Leveling" MENU_ITEM(submenu, MSG_MESH_BED_LEVELING, lcd_mesh_bedleveling); -#endif +#endif //MK1BP MENU_ITEM(gcode, MSG_AUTO_HOME, PSTR("G28 W")); MENU_ITEM(submenu, MSG_BED_CORRECTION_MENU, lcd_adjust_bed); +#ifndef MK1BP + MENU_ITEM(submenu, MSG_CALIBRATION_PINDA_MENU, lcd_pinda_calibration_menu); +#endif //MK1BP + MENU_ITEM(submenu, MSG_PID_EXTRUDER, pid_extruder); MENU_ITEM(submenu, MSG_SHOW_END_STOPS, menu_show_end_stops); +#ifndef MK1BP MENU_ITEM(gcode, MSG_CALIBRATE_BED_RESET, PSTR("M44")); +#endif //MK1BP #ifndef SNMM //MENU_ITEM(function, MSG_RESET_CALIBRATE_E, lcd_extr_cal_reset); #endif @@ -2657,35 +2844,21 @@ void lcd_mylang() { } -char reset_menu() { - int enc_dif = 0; - char cursor_pos = 0; - +void bowden_menu() { + int enc_dif = encoderDiff; + int cursor_pos = 0; lcd_implementation_clear(); - - lcd.setCursor(1, 0); - - lcd_printPGM(PSTR("Language")); - - - lcd.setCursor(1, 1); - - lcd_printPGM(PSTR("Statistics")); - - - lcd.setCursor(1, 2); - - lcd_printPGM(PSTR("Shiping prep")); - - lcd.setCursor(1, 3); - - lcd_printPGM(PSTR("All data")); - lcd.setCursor(0, 0); - lcd.print(">"); + for (int i = 0; i < 4; i++) { + lcd.setCursor(1, i); + lcd.print("Extruder "); + lcd.print(i); + lcd.print(": "); + EEPROM_read_B(EEPROM_BOWDEN_LENGTH + i * 2, &bowden_length[i]); + lcd.print(bowden_length[i] - 48); - + } enc_dif = encoderDiff; while (1) { @@ -2693,6 +2866,172 @@ char reset_menu() { manage_heater(); manage_inactivity(true); + if (abs((enc_dif - encoderDiff)) > 2) { + + if (enc_dif > encoderDiff) { + cursor_pos--; + } + + if (enc_dif < encoderDiff) { + cursor_pos++; + } + + if (cursor_pos > 3) { + cursor_pos = 3; + } + + if (cursor_pos < 0) { + cursor_pos = 0; + } + + lcd.setCursor(0, 0); + lcd.print(" "); + lcd.setCursor(0, 1); + lcd.print(" "); + lcd.setCursor(0, 2); + lcd.print(" "); + lcd.setCursor(0, 3); + lcd.print(" "); + lcd.setCursor(0, cursor_pos); + lcd.print(">"); + + enc_dif = encoderDiff; + delay(100); + } + + if (lcd_clicked()) { + while (lcd_clicked()); + delay(10); + while (lcd_clicked()); + + lcd_implementation_clear(); + while (1) { + + manage_heater(); + manage_inactivity(true); + + lcd.setCursor(1, 1); + lcd.print("Extruder "); + lcd.print(cursor_pos); + lcd.print(": "); + lcd.setCursor(13, 1); + lcd.print(bowden_length[cursor_pos] - 48); + + if (abs((enc_dif - encoderDiff)) > 2) { + if (enc_dif > encoderDiff) { + bowden_length[cursor_pos]--; + lcd.setCursor(13, 1); + lcd.print(bowden_length[cursor_pos] - 48); + enc_dif = encoderDiff; + } + + if (enc_dif < encoderDiff) { + bowden_length[cursor_pos]++; + lcd.setCursor(13, 1); + lcd.print(bowden_length[cursor_pos] - 48); + enc_dif = encoderDiff; + } + } + delay(100); + if (lcd_clicked()) { + while (lcd_clicked()); + delay(10); + while (lcd_clicked()); + EEPROM_save_B(EEPROM_BOWDEN_LENGTH + cursor_pos * 2, &bowden_length[cursor_pos]); + if (lcd_show_fullscreen_message_yes_no_and_wait_P(PSTR("Continue with another bowden?"))) { + lcd_update_enable(true); + lcd_implementation_clear(); + enc_dif = encoderDiff; + lcd.setCursor(0, cursor_pos); + lcd.print(">"); + for (int i = 0; i < 4; i++) { + lcd.setCursor(1, i); + lcd.print("Extruder "); + lcd.print(i); + lcd.print(": "); + EEPROM_read_B(EEPROM_BOWDEN_LENGTH + i * 2, &bowden_length[i]); + lcd.print(bowden_length[i] - 48); + + } + break; + } + else return; + } + } + } + } +} + +static char snmm_stop_print_menu() { //menu for choosing which filaments will be unloaded in stop print + lcd_implementation_clear(); + lcd_print_at_PGM(0,0,MSG_UNLOAD_FILAMENT); lcd.print(":"); + lcd.setCursor(0, 1); lcd.print(">"); + lcd_print_at_PGM(1,1,MSG_ALL); + lcd_print_at_PGM(1,2,MSG_USED); + lcd_print_at_PGM(1,3,MSG_CURRENT); + char cursor_pos = 1; + int enc_dif = 0; + + while (1) { + manage_heater(); + manage_inactivity(true); + if (abs((enc_dif - encoderDiff)) > 4) { + + if ((abs(enc_dif - encoderDiff)) > 1) { + if (enc_dif > encoderDiff) cursor_pos--; + if (enc_dif < encoderDiff) cursor_pos++; + if (cursor_pos > 3) cursor_pos = 3; + if (cursor_pos < 1) cursor_pos = 1; + + lcd.setCursor(0, 1); + lcd.print(" "); + lcd.setCursor(0, 2); + lcd.print(" "); + lcd.setCursor(0, 3); + lcd.print(" "); + lcd.setCursor(0, cursor_pos); + lcd.print(">"); + enc_dif = encoderDiff; + delay(100); + } + } + if (lcd_clicked()) { + while (lcd_clicked()); + delay(10); + while (lcd_clicked()); + return(cursor_pos - 1); + } + } + +} + +char choose_extruder_menu() { + + int items_no = 4; + int first = 0; + int enc_dif = 0; + char cursor_pos = 1; + + enc_dif = encoderDiff; + lcd_implementation_clear(); + + lcd_printPGM(MSG_CHOOSE_EXTRUDER); + lcd.setCursor(0, 1); + lcd.print(">"); + for (int i = 0; i < 3; i++) { + lcd_print_at_PGM(1, i + 1, MSG_EXTRUDER); + } + + while (1) { + + for (int i = 0; i < 3; i++) { + lcd.setCursor(2 + strlen_P(MSG_EXTRUDER), i+1); + lcd.print(first + i + 1); + } + + manage_heater(); + manage_inactivity(true); + if (abs((enc_dif - encoderDiff)) > 4) { if ((abs(enc_dif - encoderDiff)) > 1) { @@ -2706,10 +3045,114 @@ char reset_menu() { if (cursor_pos > 3) { cursor_pos = 3; + if (first < items_no - 3) { + first++; + lcd_implementation_clear(); + lcd_printPGM(MSG_CHOOSE_EXTRUDER); + for (int i = 0; i < 3; i++) { + lcd_print_at_PGM(1, i + 1, MSG_EXTRUDER); + } + } + } + + if (cursor_pos < 1) { + cursor_pos = 1; + if (first > 0) { + first--; + lcd_implementation_clear(); + lcd_printPGM(MSG_CHOOSE_EXTRUDER); + for (int i = 0; i < 3; i++) { + lcd_print_at_PGM(1, i + 1, MSG_EXTRUDER); + } + } + } + lcd.setCursor(0, 1); + lcd.print(" "); + lcd.setCursor(0, 2); + lcd.print(" "); + lcd.setCursor(0, 3); + lcd.print(" "); + lcd.setCursor(0, cursor_pos); + lcd.print(">"); + enc_dif = encoderDiff; + delay(100); + } + + } + + if (lcd_clicked()) { + lcd_update(2); + while (lcd_clicked()); + delay(10); + while (lcd_clicked()); + return(cursor_pos + first - 1); + + } + + } + +} + + +char reset_menu() { +#ifdef SNMM + int items_no = 5; +#else + int items_no = 4; +#endif + static int first = 0; + int enc_dif = 0; + char cursor_pos = 0; + const char *item [items_no]; + + item[0] = "Language"; + item[1] = "Statistics"; + item[2] = "Shipping prep"; + item[3] = "All Data"; +#ifdef SNMM + item[4] = "Bowden length"; +#endif // SNMM + + enc_dif = encoderDiff; + lcd_implementation_clear(); + lcd.setCursor(0, 0); + lcd.print(">"); + + while (1) { + + for (int i = 0; i < 4; i++) { + lcd.setCursor(1, i); + lcd.print(item[first + i]); + } + + manage_heater(); + manage_inactivity(true); + + if (abs((enc_dif - encoderDiff)) > 4) { + + if ((abs(enc_dif - encoderDiff)) > 1) { + if (enc_dif > encoderDiff) { + cursor_pos--; + } + + if (enc_dif < encoderDiff) { + cursor_pos++; + } + + if (cursor_pos > 3) { + cursor_pos = 3; + if (first < items_no - 4) { + first++; + lcd_implementation_clear(); + } } if (cursor_pos < 0) { cursor_pos = 0; + if (first > 0) { + first--; + lcd_implementation_clear(); + } } lcd.setCursor(0, 0); lcd.print(" "); @@ -2731,7 +3174,7 @@ char reset_menu() { while (lcd_clicked()); delay(10); while (lcd_clicked()); - return(cursor_pos); + return(cursor_pos + first); } } @@ -2785,9 +3228,14 @@ void change_extr(int extr) { //switches multiplexer for extruders disable_e1(); disable_e2(); +#ifdef SNMM + snmm_extruder = extr; +#endif + pinMode(E_MUX0_PIN, OUTPUT); pinMode(E_MUX1_PIN, OUTPUT); pinMode(E_MUX2_PIN, OUTPUT); + switch (extr) { case 1: WRITE(E_MUX0_PIN, HIGH); @@ -2822,6 +3270,15 @@ static int get_ext_nr() { //reads multiplexer input pins and return current extr } +void display_loading() { + switch (snmm_extruder) { + case 1: lcd_display_message_fullscreen_P(MSG_FILAMENT_LOADING_T1); break; + case 2: lcd_display_message_fullscreen_P(MSG_FILAMENT_LOADING_T2); break; + case 3: lcd_display_message_fullscreen_P(MSG_FILAMENT_LOADING_T3); break; + default: lcd_display_message_fullscreen_P(MSG_FILAMENT_LOADING_T0); break; + } +} + static void extr_adj(int extruder) //loading filament for SNMM { bool correct; @@ -2848,9 +3305,13 @@ static void extr_adj(int extruder) //loading filament for SNMM //if (!correct) goto START; //extr_mov(BOWDEN_LENGTH/2.f, 500); //dividing by 2 is there because of max. extrusion length limitation (x_max + y_max) //extr_mov(BOWDEN_LENGTH/2.f, 500); - extr_mov(BOWDEN_LENGTH, 500); + extr_mov(bowden_length[extruder], 500); lcd_implementation_clear(); - lcd.setCursor(0, 1); lcd_printPGM(MSG_PLEASE_WAIT); + lcd.setCursor(0, 0); lcd_printPGM(MSG_LOADING_FILAMENT); + if(strlen(MSG_LOADING_FILAMENT)>18) lcd.setCursor(0, 1); + else lcd.print(" "); + lcd.print(snmm_extruder + 1); + lcd.setCursor(0, 2); lcd_printPGM(MSG_PLEASE_WAIT); st_synchronize(); max_feedrate[E_AXIS] = 50; lcd_update_enable(true); @@ -2859,7 +3320,7 @@ static void extr_adj(int extruder) //loading filament for SNMM } -static void extr_unload() { //unloads filament +void extr_unload() { //unloads filament float tmp_motor[3] = DEFAULT_PWM_MOTOR_CURRENT; float tmp_motor_loud[3] = DEFAULT_PWM_MOTOR_CURRENT_LOUD; int8_t SilentMode; @@ -2868,10 +3329,14 @@ static void extr_unload() { //unloads filament lcd_implementation_clear(); lcd_display_message_fullscreen_P(PSTR("")); max_feedrate[E_AXIS] = 50; - lcd.setCursor(0, 1); lcd_printPGM(MSG_PLEASE_WAIT); - current_position[Z_AXIS] += 15; //lifting in Z direction to make space for extrusion - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 25, active_extruder); - + lcd.setCursor(0, 0); lcd_printPGM(MSG_UNLOADING_FILAMENT); + lcd.print(" "); + lcd.print(snmm_extruder + 1); + lcd.setCursor(0, 2); lcd_printPGM(MSG_PLEASE_WAIT); + if (current_position[Z_AXIS] < 15) { + current_position[Z_AXIS] += 15; //lifting in Z direction to make space for extrusion + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 25, active_extruder); + } current_position[E_AXIS] += 10; //extrusion plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 10, active_extruder); @@ -2899,9 +3364,9 @@ static void extr_unload() { //unloads filament } max_feedrate[E_AXIS] = 80; - current_position[E_AXIS] -= (BOWDEN_LENGTH + 60 + FIL_LOAD_LENGTH) / 2; + current_position[E_AXIS] -= (bowden_length[snmm_extruder] + 60 + FIL_LOAD_LENGTH) / 2; plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 500, active_extruder); - current_position[E_AXIS] -= (BOWDEN_LENGTH + 60 + FIL_LOAD_LENGTH) / 2; + current_position[E_AXIS] -= (bowden_length[snmm_extruder] + 60 + FIL_LOAD_LENGTH) / 2; plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 500, active_extruder); st_synchronize(); //digipot_init(); @@ -2948,6 +3413,13 @@ static void extr_adj_3() { extr_adj(3); } +static void load_all() { + for (int i = 0; i < 4; i++) { + change_extr(i); + extr_adj(i); + } +} + //wrapper functions for changing extruders static void extr_change_0() { change_extr(0); @@ -2967,6 +3439,51 @@ static void extr_change_3() { } //wrapper functions for unloading filament +void extr_unload_all() { + if (degHotend0() > EXTRUDE_MINTEMP) { + for (int i = 0; i < 4; i++) { + change_extr(i); + extr_unload(); + } + } + else { + lcd_implementation_clear(); + lcd.setCursor(0, 0); + lcd_printPGM(MSG_ERROR); + lcd.setCursor(0, 2); + lcd_printPGM(MSG_PREHEAT_NOZZLE); + delay(2000); + lcd_implementation_clear(); + lcd_return_to_status(); + } +} + +//unloading just used filament (for snmm) + +void extr_unload_used() { + if (degHotend0() > EXTRUDE_MINTEMP) { + for (int i = 0; i < 4; i++) { + if (snmm_filaments_used & (1 << i)) { + change_extr(i); + extr_unload(); + } + } + snmm_filaments_used = 0; + } + else { + lcd_implementation_clear(); + lcd.setCursor(0, 0); + lcd_printPGM(MSG_ERROR); + lcd.setCursor(0, 2); + lcd_printPGM(MSG_PREHEAT_NOZZLE); + delay(2000); + lcd_implementation_clear(); + lcd_return_to_status(); + } +} + + + static void extr_unload_0() { change_extr(0); extr_unload(); @@ -2989,23 +3506,24 @@ static void fil_load_menu() { START_MENU(); MENU_ITEM(back, MSG_MAIN, lcd_main_menu); - MENU_ITEM(function, PSTR("Load filament 1"), extr_adj_0); - MENU_ITEM(function, PSTR("Load filament 2 "), extr_adj_1); - MENU_ITEM(function, PSTR("Load filament 3"), extr_adj_2); - MENU_ITEM(function, PSTR("Load filament 4"), extr_adj_3); + MENU_ITEM(function, MSG_LOAD_ALL, load_all); + MENU_ITEM(function, MSG_LOAD_FILAMENT_1, extr_adj_0); + MENU_ITEM(function, MSG_LOAD_FILAMENT_2, extr_adj_1); + MENU_ITEM(function, MSG_LOAD_FILAMENT_3, extr_adj_2); + MENU_ITEM(function, MSG_LOAD_FILAMENT_4, extr_adj_3); END_MENU(); } - static void fil_unload_menu() { START_MENU(); MENU_ITEM(back, MSG_MAIN, lcd_main_menu); - MENU_ITEM(function, PSTR("Unload filament 1"), extr_unload_0); - MENU_ITEM(function, PSTR("Unload filament 2"), extr_unload_1); - MENU_ITEM(function, PSTR("Unload filament 3"), extr_unload_2); - MENU_ITEM(function, PSTR("Unload filament 4"), extr_unload_3); + MENU_ITEM(function, MSG_UNLOAD_ALL, extr_unload_all); + MENU_ITEM(function, MSG_UNLOAD_FILAMENT_1, extr_unload_0); + MENU_ITEM(function, MSG_UNLOAD_FILAMENT_2, extr_unload_1); + MENU_ITEM(function, MSG_UNLOAD_FILAMENT_3, extr_unload_2); + MENU_ITEM(function, MSG_UNLOAD_FILAMENT_4, extr_unload_3); END_MENU(); } @@ -3013,10 +3531,10 @@ static void fil_unload_menu() static void change_extr_menu(){ START_MENU(); MENU_ITEM(back, MSG_MAIN, lcd_main_menu); - MENU_ITEM(function, PSTR("Extruder 1"), extr_change_0); - MENU_ITEM(function, PSTR("Extruder 2"), extr_change_1); - MENU_ITEM(function, PSTR("Extruder 3"), extr_change_2); - MENU_ITEM(function, PSTR("Extruder 4"), extr_change_3); + MENU_ITEM(function, MSG_EXTRUDER_1, extr_change_0); + MENU_ITEM(function, MSG_EXTRUDER_2, extr_change_1); + MENU_ITEM(function, MSG_EXTRUDER_3, extr_change_2); + MENU_ITEM(function, MSG_EXTRUDER_4, extr_change_3); END_MENU(); } @@ -3158,6 +3676,8 @@ void lcd_confirm_print() } + + static void lcd_main_menu() { @@ -3166,7 +3686,8 @@ static void lcd_main_menu() // Majkl superawesome menu - MENU_ITEM(back, MSG_WATCH, lcd_status_screen); + + MENU_ITEM(back, MSG_WATCH, lcd_status_screen); /* if (farm_mode && !IS_SD_PRINTING ) { @@ -3216,9 +3737,7 @@ static void lcd_main_menu() }*/ - - - if ( ( IS_SD_PRINTING || is_usb_printing ) && (current_position[Z_AXIS] < Z_HEIGHT_HIDE_LIVE_ADJUST_MENU) && !homing_flag) + if ( ( IS_SD_PRINTING || is_usb_printing ) && (current_position[Z_AXIS] < Z_HEIGHT_HIDE_LIVE_ADJUST_MENU) && !homing_flag && !mesh_bed_leveling_flag) { MENU_ITEM(submenu, MSG_BABYSTEP_Z, lcd_babystep_z);//8 } @@ -3237,15 +3756,17 @@ static void lcd_main_menu() { if (card.isFileOpen()) { - if (card.sdprinting) - { - MENU_ITEM(function, MSG_PAUSE_PRINT, lcd_sdcard_pause); + if (mesh_bed_leveling_flag == false && homing_flag == false) { + if (card.sdprinting) + { + MENU_ITEM(function, MSG_PAUSE_PRINT, lcd_sdcard_pause); + } + else + { + MENU_ITEM(function, MSG_RESUME_PRINT, lcd_sdcard_resume); + } + MENU_ITEM(submenu, MSG_STOP_PRINT, lcd_sdcard_stop); } - else - { - MENU_ITEM(function, MSG_RESUME_PRINT, lcd_sdcard_resume); - } - MENU_ITEM(submenu, MSG_STOP_PRINT, lcd_sdcard_stop); } else { @@ -3327,6 +3848,17 @@ static void lcd_silent_mode_set_tune() { lcd_goto_menu(lcd_tune_menu, 9); } +static void lcd_colorprint_change() { + + enquecommand_P(PSTR("M600")); + + custom_message = true; + custom_message_type = 2; //just print status message + lcd_setstatuspgm(MSG_FINISHING_MOVEMENTS); + lcd_return_to_status(); + lcdDrawUpdate = 3; +} + static void lcd_tune_menu() { EEPROM_read(EEPROM_SILENT, (uint8_t*)&SilentModeMenu, sizeof(SilentModeMenu)); @@ -3343,7 +3875,7 @@ static void lcd_tune_menu() MENU_ITEM_EDIT(int3, MSG_FAN_SPEED, &fanSpeed, 0, 255);//5 MENU_ITEM_EDIT(int3, MSG_FLOW, &extrudemultiply, 10, 999);//6 #ifdef FILAMENTCHANGEENABLE - MENU_ITEM(gcode, MSG_FILAMENTCHANGE, PSTR("M600"));//7 + MENU_ITEM(function, MSG_FILAMENTCHANGE, lcd_colorprint_change);//7 #endif if (SilentModeMenu == 0) { @@ -3438,23 +3970,27 @@ void lcd_sdcard_stop() } if ((int32_t)encoderPosition == 2) { - cancel_heatup = true; + cancel_heatup = true; #ifdef MESH_BED_LEVELING mbl.active = false; #endif // Stop the stoppers, update the position from the stoppers. - planner_abort_hard(); - // Because the planner_abort_hard() initialized current_position[Z] from the stepper, - // Z baystep is no more applied. Reset it. - babystep_reset(); + if (mesh_bed_leveling_flag == false && homing_flag == false) { + planner_abort_hard(); + // Because the planner_abort_hard() initialized current_position[Z] from the stepper, + // Z baystep is no more applied. Reset it. + babystep_reset(); + } // Clean the input command queue. cmdqueue_reset(); lcd_setstatuspgm(MSG_PRINT_ABORTED); + lcd_update(2); card.sdprinting = false; card.closefile(); stoptime = millis(); - unsigned long t = (stoptime - starttime) / 1000; //time in s + unsigned long t = (stoptime - starttime - pause_time) / 1000; //time in s + pause_time = 0; save_statistics(total_filament_used, t); lcd_return_to_status(); @@ -3687,31 +4223,34 @@ static void lcd_selftest() _progress = lcd_selftest_screen(0, _progress, 3, true, 2000); _result = lcd_selftest_fan_dialog(1); } - + if (_result) { _progress = lcd_selftest_screen(1, _progress, 3, true, 2000); //_progress = lcd_selftest_screen(2, _progress, 3, true, 2000); _result = true;// lcd_selfcheck_endstops(); } - + if (_result) { _progress = lcd_selftest_screen(3, _progress, 3, true, 1000); - _result = lcd_selfcheck_check_heater(false); + //_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 + //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); - _result = lcd_selfcheck_axis(X_AXIS, X_MAX_POS); - + //_result = lcd_selfcheck_axis(X_AXIS, X_MAX_POS); + homeaxis(X_AXIS); + } if (_result) { _progress = lcd_selftest_screen(4, _progress, 3, true, 0); + + _result = lcd_selfcheck_pulleys(X_AXIS); } @@ -3719,13 +4258,13 @@ static void lcd_selftest() if (_result) { _progress = lcd_selftest_screen(5, _progress, 3, true, 1500); - _result = lcd_selfcheck_axis(Y_AXIS, Y_MAX_POS); + //_result = lcd_selfcheck_axis(Y_AXIS, Y_MAX_POS); } if (_result) { _progress = lcd_selftest_screen(5, _progress, 3, true, 0); - _result = lcd_selfcheck_pulleys(Y_AXIS); + //_result = lcd_selfcheck_pulleys(Y_AXIS); } @@ -3734,14 +4273,14 @@ static void lcd_selftest() current_position[X_AXIS] = current_position[X_AXIS] - 3; current_position[Y_AXIS] = current_position[Y_AXIS] - 14; _progress = lcd_selftest_screen(6, _progress, 3, true, 1500); - _result = lcd_selfcheck_axis(2, Z_MAX_POS); - enquecommand_P(PSTR("G28 W")); + //_result = lcd_selfcheck_axis(2, Z_MAX_POS); + //enquecommand_P(PSTR("G28 W")); } if (_result) { _progress = lcd_selftest_screen(7, _progress, 3, true, 2000); - _result = lcd_selfcheck_check_heater(true); + //_result = lcd_selfcheck_check_heater(true); } if (_result) { @@ -3758,7 +4297,7 @@ static void lcd_selftest() if (_result) { - LCD_ALERTMESSAGERPGM(MSG_SELFTEST_OK); + LCD_ALERTMESSAGERPGM(MSG_SELFTEST_OK); } else { @@ -3766,6 +4305,7 @@ static void lcd_selftest() } } + static bool lcd_selfcheck_axis(int _axis, int _travel) { bool _stepdone = false; @@ -3956,22 +4496,30 @@ static bool lcd_selfcheck_check_heater(bool _isbed) int _checked_snapshot = (_isbed) ? degBed() : degHotend(0); int _opposite_snapshot = (_isbed) ? degHotend(0) : degBed(); - int _cycles = (_isbed) ? 120 : 30; + int _cycles = (_isbed) ? 180 : 60; //~ 90s / 30s - target_temperature[0] = (_isbed) ? 0 : 100; + target_temperature[0] = (_isbed) ? 0 : 200; target_temperature_bed = (_isbed) ? 100 : 0; manage_heater(); manage_inactivity(true); do { _counter++; - (_counter < _cycles) ? _docycle = true : _docycle = false; + _docycle = (_counter < _cycles) ? true : false; manage_heater(); manage_inactivity(true); _progress = (_isbed) ? lcd_selftest_screen(7, _progress, 2, false, 400) : lcd_selftest_screen(3, _progress, 2, false, 400); + /*if (_isbed) { + MYSERIAL.print("Bed temp:"); + MYSERIAL.println(degBed()); + } + else { + MYSERIAL.print("Hotend temp:"); + MYSERIAL.println(degHotend(0)); + }*/ - } while (_docycle); + } while (_docycle); target_temperature[0] = 0; target_temperature_bed = 0; @@ -3979,10 +4527,16 @@ static bool lcd_selfcheck_check_heater(bool _isbed) int _checked_result = (_isbed) ? degBed() - _checked_snapshot : degHotend(0) - _checked_snapshot; int _opposite_result = (_isbed) ? degHotend(0) - _opposite_snapshot : degBed() - _opposite_snapshot; - - if (_opposite_result < (_isbed) ? 10 : 3) + /* + MYSERIAL.println(""); + MYSERIAL.print("Checked result:"); + MYSERIAL.println(_checked_result); + MYSERIAL.print("Opposite result:"); + MYSERIAL.println(_opposite_result); + */ + if (_opposite_result < ((_isbed) ? 10 : 3)) { - if (_checked_result >= (_isbed) ? 3 : 10) + if (_checked_result >= ((_isbed) ? 3 : 10)) { _stepresult = true; } @@ -4101,7 +4655,7 @@ static bool lcd_selftest_fan_dialog(int _fan) { bool _result = true; int _errno = 6; - + switch (_fan) { case 0: fanSpeed = 0; @@ -4109,7 +4663,7 @@ static bool lcd_selftest_fan_dialog(int _fan) setExtruderAutoFanState(EXTRUDER_0_AUTO_FAN_PIN, 1); //extruder fan delay(2000); //delay_keep_alive would turn off extruder fan, because temerature is too low manage_heater(); //count average fan speed from 2s delay and turn off fans - if (!fan_speed[0]) _result = false; + if (!fan_speed[0]) _result = false; /*SERIAL_ECHOPGM("Extruder fan speed: "); MYSERIAL.println(fan_speed[0]); SERIAL_ECHOPGM("Print fan speed: "); @@ -4132,7 +4686,6 @@ static bool lcd_selftest_fan_dialog(int _fan) MYSERIAL.print(fan_speed[1]);*/ break; } - if (!_result) { const char *_err; @@ -4145,7 +4698,7 @@ static int lcd_selftest_screen(int _step, int _progress, int _progress_scale, bo { //SERIAL_ECHOPGM("Step:"); //MYSERIAL.println(_step); - + lcd_next_update_millis = millis() + (LCD_UPDATE_INTERVAL * 10000); int _step_block = 0; @@ -4179,7 +4732,8 @@ static int lcd_selftest_screen(int _step, int _progress, int _progress_scale, bo lcd_print_at_PGM(0, 3, PSTR("Print fan:")); lcd.setCursor(14, 3); (_step < 1) ? lcd.print(_indicator) : lcd.print("OK"); - } else if (_step != 9) + } + else if (_step != 9) { //SERIAL_ECHOLNPGM("Other tests"); _step_block = 3; @@ -4203,6 +4757,7 @@ static int lcd_selftest_screen(int _step, int _progress, int _progress_scale, bo 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) { lcd.setCursor(_col, _row); @@ -4234,7 +4789,7 @@ static void lcd_selftest_screen_step(int _row, int _col, int _state, const char static void lcd_quick_feedback() { lcdDrawUpdate = 2; - button_pressed = false; + button_pressed = false; lcd_implementation_quick_feedback(); } @@ -4452,7 +5007,7 @@ void lcd_update(uint8_t lcdDrawUpdateOverride) lcd_timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS; } - /*if (LCD_CLICKED)*/ lcd_timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS; + if (LCD_CLICKED) lcd_timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS; #endif//ULTIPANEL #ifdef DOGLCD // Changes due to different driver architecture of the DOGM display @@ -4589,35 +5144,41 @@ void lcd_buttons_update() #if BTN_ENC > 0 if (lcd_update_enabled == true) { //if we are in non-modal mode, long press can be used and short press triggers with button release if (READ(BTN_ENC) == 0) { //button is pressed - - if (button_pressed == false && long_press_active == false) { - if (currentMenu != lcd_move_z) { - savedMenu = currentMenu; - savedEncoderPosition = encoderPosition; + lcd_timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS; + if (millis() > button_blanking_time) { + button_blanking_time = millis() + BUTTON_BLANKING_TIME; + if (button_pressed == false && long_press_active == false) { + if (currentMenu != lcd_move_z) { + savedMenu = currentMenu; + savedEncoderPosition = encoderPosition; + } + long_press_timer = millis(); + button_pressed = true; } - long_press_timer = millis(); - button_pressed = true; - } - else { - if (millis() - long_press_timer > LONG_PRESS_TIME) { //long press activated - - long_press_active = true; - move_menu_scale = 1.0; - lcd_goto_menu(lcd_move_z); + else { + if (millis() - long_press_timer > LONG_PRESS_TIME) { //long press activated + + long_press_active = true; + move_menu_scale = 1.0; + lcd_goto_menu(lcd_move_z); + } } } } else { //button not pressed if (button_pressed) { //button was released + button_blanking_time = millis() + BUTTON_BLANKING_TIME; + if (long_press_active == false) { //button released before long press gets activated if (currentMenu == lcd_move_z) { //return to previously active menu and previous encoder position - lcd_goto_menu(savedMenu, savedEncoderPosition); + lcd_goto_menu(savedMenu, savedEncoderPosition); } else { newbutton |= EN_C; } } + else if (currentMenu == lcd_move_z) lcd_quick_feedback(); //button_pressed is set back to false via lcd_quick_feedback function } else { @@ -4720,7 +5281,9 @@ void lcd_buzz(long duration, uint16_t freq) bool lcd_clicked() { - return LCD_CLICKED; + bool clicked = LCD_CLICKED; + if(clicked) button_pressed = false; + return clicked; } #endif//ULTIPANEL diff --git a/Firmware/ultralcd.h b/Firmware/ultralcd.h index 76136ff8f..a9a1cbf05 100644 --- a/Firmware/ultralcd.h +++ b/Firmware/ultralcd.h @@ -91,6 +91,9 @@ void lcd_mylang(); #define LCD_COMMAND_LOAD_FILAMENT 1 #define LCD_COMMAND_STOP_PRINT 2 #define LCD_COMMAND_FARM_MODE_CONFIRM 4 + #define LCD_COMMAND_LONG_PAUSE 5 + #define LCD_COMMAND_LONG_PAUSE_RESUME 6 + #define LCD_COMMAND_PID_EXTRUDER 7 extern unsigned long lcd_timeoutToStatus; extern int lcd_commands_type; @@ -100,7 +103,12 @@ void lcd_mylang(); extern int farm_timer; extern int farm_status; +#ifdef SNMM + extern uint8_t snmm_extruder; +#endif // SNMM + extern bool cancel_heatup; + extern bool isPrintPaused; #ifdef FILAMENT_LCD_DISPLAY extern unsigned long message_millis; @@ -200,6 +208,7 @@ extern void lcd_implementation_print_at(uint8_t x, uint8_t y, const char *str); void change_extr(int extr); +static void lcd_colorprint_change(); static int get_ext_nr(); static void extr_adj(int extruder); static void extr_adj_0(); @@ -213,6 +222,10 @@ static void extr_unload_1(); static void extr_unload_2(); static void extr_unload_3(); static void lcd_disable_farm_mode(); +void extr_unload_all(); +void extr_unload_used(); +void extr_unload(); +static char snmm_stop_print_menu(); void stack_error(); static void lcd_ping_allert(); @@ -233,5 +246,16 @@ void lcd_extr_cal_reset(); union MenuData; +void bowden_menu(); char reset_menu(); +char choose_extruder_menu(); + +void lcd_pinda_calibration_menu(); +void lcd_calibrate_pinda(); +void lcd_temp_calibration_set(); + +void display_loading(); + +void lcd_service_mode_show_result(); + #endif //ULTRALCD_H \ No newline at end of file diff --git a/Firmware/ultralcd_implementation_hitachi_HD44780.h b/Firmware/ultralcd_implementation_hitachi_HD44780.h index c4fb53ac9..ae0bb09f5 100644 --- a/Firmware/ultralcd_implementation_hitachi_HD44780.h +++ b/Firmware/ultralcd_implementation_hitachi_HD44780.h @@ -709,12 +709,13 @@ static void lcd_implementation_status_screen() lcd_printPGM(PSTR(" ")); lcd.print(LCD_STR_FEEDRATE[0]); lcd.print(itostr3(feedmultiply)); - lcd_printPGM(PSTR("% ")); + lcd_printPGM(PSTR("% ")); lcd.setCursor(8, 0); lcd.print(itostr3(fan_speed[0])); lcd.setCursor(8, 1); lcd.print(itostr3(fan_speed[1])); + #else //Print Feedrate lcd.setCursor(LCD_WIDTH - 8-2, 1); @@ -781,15 +782,17 @@ static void lcd_implementation_status_screen() } else { - lcd.setCursor(LCD_WIDTH - 8 - 2, 2); - lcd_printPGM(PSTR(" ")); - } - #ifdef SNMM lcd_printPGM(PSTR(" E")); - lcd.print(get_ext_nr()+1); - + lcd.print(get_ext_nr() + 1); + +#else + lcd.setCursor(LCD_WIDTH - 8 - 2, 2); + lcd_printPGM(PSTR(" ")); #endif + } + + //Print time elapsed lcd.setCursor(LCD_WIDTH - 8 -1, 2); @@ -797,7 +800,7 @@ static void lcd_implementation_status_screen() lcd.print(LCD_STR_CLOCK[0]); if(starttime != 0) { - uint16_t time = millis()/60000 - starttime/60000; + uint16_t time = millis() / 60000 - starttime / 60000; lcd.print(itostr2(time/60)); lcd.print(':'); lcd.print(itostr2(time%60)); @@ -953,6 +956,39 @@ static void lcd_implementation_status_screen() { lcd.print(lcd_status_message); } + // PID tuning in progress + if (custom_message_type == 3) { + lcd.print(lcd_status_message); + if (pid_cycle <= pid_number_of_cycles && custom_message_state > 0) { + lcd.setCursor(10, 3); + lcd.print(itostr3(pid_cycle)); + + lcd.print('/'); + lcd.print(itostr3left(pid_number_of_cycles)); + } + } + // PINDA temp calibration in progress + if (custom_message_type == 4) { + char progress[4]; + lcd.setCursor(0, 3); + lcd_printPGM(MSG_TEMP_CALIBRATION); + lcd.setCursor(12, 3); + sprintf(progress, "%d/6", custom_message_state); + lcd.print(progress); + } + // temp compensation preheat + if (custom_message_type == 5) { + lcd.setCursor(0, 3); + lcd_printPGM(MSG_PINDA_PREHEAT); + if (custom_message_state <= PINDA_HEAT_T) { + lcd_printPGM(PSTR(": ")); + lcd.print(custom_message_state); //seconds + lcd.print(' '); + + } + } + + } else { diff --git a/Firmware/util.cpp b/Firmware/util.cpp index 6791c95fa..8c575ca84 100644 --- a/Firmware/util.cpp +++ b/Firmware/util.cpp @@ -1,288 +1,288 @@ -#include "Configuration.h" - -#include "ultralcd.h" -#include "language.h" -#include "util.h" - -// Allocate the version string in the program memory. Otherwise the string lands either on the stack or in the global RAM. -const char FW_VERSION_STR[] PROGMEM = FW_version; - -const char* FW_VERSION_STR_P() -{ - return FW_VERSION_STR; -} - -const char FW_PRUSA3D_MAGIC_STR[] PROGMEM = FW_PRUSA3D_MAGIC; - -const char* FW_PRUSA3D_MAGIC_STR_P() -{ - return FW_PRUSA3D_MAGIC_STR; -} - -const char STR_REVISION_DEV [] PROGMEM = "dev"; -const char STR_REVISION_ALPHA[] PROGMEM = "alpha"; -const char STR_REVISION_BETA [] PROGMEM = "beta"; -const char STR_REVISION_RC [] PROGMEM = "rc"; - -inline bool is_whitespace_or_nl(char c) -{ - return c == ' ' || c == '\t' || c == '\n' || c == 'r'; -} - -inline bool is_whitespace_or_nl_or_eol(char c) -{ - return c == 0 || c == ' ' || c == '\t' || c == '\n' || c == '\r'; -} - -inline bool is_digit(char c) -{ - return c >= '0' && c <= '9'; -} - -// Parse a major.minor.revision version number. -// Return true if valid. -inline bool parse_version(const char *str, uint16_t version[4]) -{ -#if 0 - SERIAL_ECHOPGM("Parsing version string "); - SERIAL_ECHO(str); - SERIAL_ECHOLNPGM(""); -#endif - - const char *major = str; - const char *p = str; - while (is_digit(*p)) ++ p; - if (*p != '.') - return false; - const char *minor = ++ p; - while (is_digit(*p)) ++ p; - if (*p != '.') - return false; - const char *rev = ++ p; - while (is_digit(*p)) ++ p; - if (! is_whitespace_or_nl_or_eol(*p) && *p != '-') - return false; - - char *endptr = NULL; - version[0] = strtol(major, &endptr, 10); - if (endptr != minor - 1) - return false; - version[1] = strtol(minor, &endptr, 10); - if (endptr != rev - 1) - return false; - version[2] = strtol(rev, &endptr, 10); - if (endptr != p) - return false; - - version[3] = FIRMWARE_REVISION_RELEASED; - if (*p ++ == '-') { - const char *q = p; - while (! is_whitespace_or_nl_or_eol(*q)) - ++ q; - uint8_t n = q - p; - if (n == strlen_P(STR_REVISION_DEV) && strncmp_P(p, STR_REVISION_DEV, n) == 0) - version[3] = FIRMWARE_REVISION_DEV; - else if (n == strlen_P(STR_REVISION_ALPHA) && strncmp_P(p, STR_REVISION_ALPHA, n) == 0) - version[3] = FIRMWARE_REVISION_ALPHA; - else if (n == strlen_P(STR_REVISION_BETA) && strncmp_P(p, STR_REVISION_BETA, n) == 0) - version[3] = FIRMWARE_REVISION_BETA; - else if ((n == 2 || n == 3) && p[0] == 'r' && p[1] == 'c') { - if (n == 2) - version[3] = FIRMWARE_REVISION_RC; - else { - if (is_digit(p[2])) - version[3] = FIRMWARE_REVISION_RC + p[2] - '1'; - else - return false; - } - } else - return false; - } - -#if 0 - SERIAL_ECHOPGM("Version parsed, major: "); - SERIAL_ECHO(version[0]); - SERIAL_ECHOPGM(", minor: "); - SERIAL_ECHO(version[1]); - SERIAL_ECHOPGM(", revision: "); - SERIAL_ECHO(version[2]); - SERIAL_ECHOPGM(", flavor: "); - SERIAL_ECHO(version[3]); - SERIAL_ECHOLNPGM(""); -#endif - return true; -} - -inline bool strncmp_PP(const char *p1, const char *p2, uint8_t n) -{ - for (; n > 0; -- n, ++ p1, ++ p2) { - if (pgm_read_byte(p1) < pgm_read_byte(p2)) - return -1; - if (pgm_read_byte(p1) > pgm_read_byte(p2)) - return 1; - if (pgm_read_byte(p1) == 0) - return 0; - } - return 0; -} - -// Parse a major.minor.revision version number. -// Return true if valid. -inline bool parse_version_P(const char *str, uint16_t version[4]) -{ -#if 0 - SERIAL_ECHOPGM("Parsing version string "); - SERIAL_ECHORPGM(str); - SERIAL_ECHOLNPGM(""); -#endif - - const char *major = str; - const char *p = str; - while (is_digit(char(pgm_read_byte(p)))) ++ p; - if (pgm_read_byte(p) != '.') - return false; - const char *minor = ++ p; - while (is_digit(char(pgm_read_byte(p)))) ++ p; - if (pgm_read_byte(p) != '.') - return false; - const char *rev = ++ p; - while (is_digit(char(pgm_read_byte(p)))) ++ p; - if (! is_whitespace_or_nl_or_eol(char(pgm_read_byte(p))) && pgm_read_byte(p) != '-') - return false; - - char buf[5]; - uint8_t n = minor - major - 1; - if (n > 4) - return false; - memcpy_P(buf, major, n); buf[n] = 0; - char *endptr = NULL; - version[0] = strtol(buf, &endptr, 10); - if (*endptr != 0) - return false; - n = rev - minor - 1; - if (n > 4) - return false; - memcpy_P(buf, minor, n); buf[n] = 0; - version[1] = strtol(buf, &endptr, 10); - if (*endptr != 0) - return false; - n = p - rev; - if (n > 4) - return false; - memcpy_P(buf, rev, n); - buf[n] = 0; - version[2] = strtol(buf, &endptr, 10); - if (*endptr != 0) - return false; - - version[3] = FIRMWARE_REVISION_RELEASED; - if (pgm_read_byte(p ++) == '-') { - const char *q = p; - while (! is_whitespace_or_nl_or_eol(char(pgm_read_byte(q)))) - ++ q; - n = q - p; - if (n == strlen_P(STR_REVISION_DEV) && strncmp_PP(p, STR_REVISION_DEV, n) == 0) - version[3] = FIRMWARE_REVISION_DEV; - else if (n == strlen_P(STR_REVISION_ALPHA) && strncmp_PP(p, STR_REVISION_ALPHA, n) == 0) - version[3] = FIRMWARE_REVISION_ALPHA; - else if (n == strlen_P(STR_REVISION_BETA) && strncmp_PP(p, STR_REVISION_BETA, n) == 0) - version[3] = FIRMWARE_REVISION_BETA; - else if ((n == 2 || n == 3) && strncmp_PP(p, STR_REVISION_RC, 2) == 0) { - if (n == 2) - version[3] = FIRMWARE_REVISION_RC; - else { - p += 2; - if (is_digit(pgm_read_byte(p))) - version[3] = FIRMWARE_REVISION_RC + pgm_read_byte(p) - '1'; - else - return false; - } - } else - return false; - } - -#if 0 - SERIAL_ECHOPGM("Version parsed, major: "); - SERIAL_ECHO(version[0]); - SERIAL_ECHOPGM(", minor: "); - SERIAL_ECHO(version[1]); - SERIAL_ECHOPGM(", revision: "); - SERIAL_ECHO(version[2]); - SERIAL_ECHOPGM(", flavor: "); - SERIAL_ECHO(version[3]); - SERIAL_ECHOLNPGM(""); -#endif - return true; -} - -// 1 - yes, 0 - false, -1 - error; -inline int8_t is_provided_version_newer(const char *version_string) -{ - uint16_t ver_gcode[3], ver_current[3]; - if (! parse_version(version_string, ver_gcode)) - return -1; - if (! parse_version_P(FW_VERSION_STR, ver_current)) - return 0; // this shall not happen - for (uint8_t i = 0; i < 3; ++ i) - if (ver_gcode[i] > ver_current[i]) - return 1; - return 0; -} - -bool show_upgrade_dialog_if_version_newer(const char *version_string) -{ - uint16_t ver_gcode[4], ver_current[4]; - if (! parse_version(version_string, ver_gcode)) { -// SERIAL_PROTOCOLLNPGM("parse_version failed"); - return false; - } - if (! parse_version_P(FW_VERSION_STR, ver_current)) { -// SERIAL_PROTOCOLLNPGM("parse_version_P failed"); - return false; // this shall not happen - } -// SERIAL_PROTOCOLLNPGM("versions parsed"); - bool upgrade = false; - for (uint8_t i = 0; i < 4; ++ i) { - if (ver_gcode[i] > ver_current[i]) { - upgrade = true; - break; - } else if (ver_gcode[i] < ver_current[i]) - break; - } - - if (upgrade) { - lcd_display_message_fullscreen_P(MSG_NEW_FIRMWARE_AVAILABLE); - lcd_print_at_PGM(0, 2, PSTR("")); - for (const char *c = version_string; ! is_whitespace_or_nl_or_eol(*c); ++ c) - lcd_implementation_write(*c); - lcd_print_at_PGM(0, 3, MSG_NEW_FIRMWARE_PLEASE_UPGRADE); - tone(BEEPER, 1000); - delay_keep_alive(50); - noTone(BEEPER); - delay_keep_alive(500); - tone(BEEPER, 1000); - delay_keep_alive(50); - noTone(BEEPER); - lcd_wait_for_click(); - lcd_update_enable(true); - lcd_implementation_clear(); - lcd_update(); - } - - // Succeeded. - return true; -} - -void update_current_firmware_version_to_eeprom() -{ - for (int8_t i = 0; i < FW_PRUSA3D_MAGIC_LEN; ++ i) - eeprom_update_byte((uint8_t*)(EEPROM_FIRMWARE_PRUSA_MAGIC+i), pgm_read_byte(FW_PRUSA3D_MAGIC_STR+i)); - uint16_t ver_current[4]; - if (parse_version_P(FW_VERSION_STR, ver_current)) { - eeprom_update_word((uint16_t*)EEPROM_FIRMWARE_VERSION_MAJOR, ver_current[0]); - eeprom_update_word((uint16_t*)EEPROM_FIRMWARE_VERSION_MINOR, ver_current[1]); - eeprom_update_word((uint16_t*)EEPROM_FIRMWARE_VERSION_REVISION, ver_current[2]); - // See FirmwareRevisionFlavorType for the definition of firmware flavors. - eeprom_update_word((uint16_t*)EEPROM_FIRMWARE_VERSION_FLAVOR, ver_current[3]); - } -} +#include "Configuration.h" + +#include "ultralcd.h" +#include "language.h" +#include "util.h" + +// Allocate the version string in the program memory. Otherwise the string lands either on the stack or in the global RAM. +const char FW_VERSION_STR[] PROGMEM = FW_version; + +const char* FW_VERSION_STR_P() +{ + return FW_VERSION_STR; +} + +const char FW_PRUSA3D_MAGIC_STR[] PROGMEM = FW_PRUSA3D_MAGIC; + +const char* FW_PRUSA3D_MAGIC_STR_P() +{ + return FW_PRUSA3D_MAGIC_STR; +} + +const char STR_REVISION_DEV [] PROGMEM = "dev"; +const char STR_REVISION_ALPHA[] PROGMEM = "alpha"; +const char STR_REVISION_BETA [] PROGMEM = "beta"; +const char STR_REVISION_RC [] PROGMEM = "rc"; + +inline bool is_whitespace_or_nl(char c) +{ + return c == ' ' || c == '\t' || c == '\n' || c == 'r'; +} + +inline bool is_whitespace_or_nl_or_eol(char c) +{ + return c == 0 || c == ' ' || c == '\t' || c == '\n' || c == '\r'; +} + +inline bool is_digit(char c) +{ + return c >= '0' && c <= '9'; +} + +// Parse a major.minor.revision version number. +// Return true if valid. +inline bool parse_version(const char *str, uint16_t version[4]) +{ +#if 0 + SERIAL_ECHOPGM("Parsing version string "); + SERIAL_ECHO(str); + SERIAL_ECHOLNPGM(""); +#endif + + const char *major = str; + const char *p = str; + while (is_digit(*p)) ++ p; + if (*p != '.') + return false; + const char *minor = ++ p; + while (is_digit(*p)) ++ p; + if (*p != '.') + return false; + const char *rev = ++ p; + while (is_digit(*p)) ++ p; + if (! is_whitespace_or_nl_or_eol(*p) && *p != '-') + return false; + + char *endptr = NULL; + version[0] = strtol(major, &endptr, 10); + if (endptr != minor - 1) + return false; + version[1] = strtol(minor, &endptr, 10); + if (endptr != rev - 1) + return false; + version[2] = strtol(rev, &endptr, 10); + if (endptr != p) + return false; + + version[3] = FIRMWARE_REVISION_RELEASED; + if (*p ++ == '-') { + const char *q = p; + while (! is_whitespace_or_nl_or_eol(*q)) + ++ q; + uint8_t n = q - p; + if (n == strlen_P(STR_REVISION_DEV) && strncmp_P(p, STR_REVISION_DEV, n) == 0) + version[3] = FIRMWARE_REVISION_DEV; + else if (n == strlen_P(STR_REVISION_ALPHA) && strncmp_P(p, STR_REVISION_ALPHA, n) == 0) + version[3] = FIRMWARE_REVISION_ALPHA; + else if (n == strlen_P(STR_REVISION_BETA) && strncmp_P(p, STR_REVISION_BETA, n) == 0) + version[3] = FIRMWARE_REVISION_BETA; + else if ((n == 2 || n == 3) && p[0] == 'r' && p[1] == 'c') { + if (n == 2) + version[3] = FIRMWARE_REVISION_RC; + else { + if (is_digit(p[2])) + version[3] = FIRMWARE_REVISION_RC + p[2] - '1'; + else + return false; + } + } else + return false; + } + +#if 0 + SERIAL_ECHOPGM("Version parsed, major: "); + SERIAL_ECHO(version[0]); + SERIAL_ECHOPGM(", minor: "); + SERIAL_ECHO(version[1]); + SERIAL_ECHOPGM(", revision: "); + SERIAL_ECHO(version[2]); + SERIAL_ECHOPGM(", flavor: "); + SERIAL_ECHO(version[3]); + SERIAL_ECHOLNPGM(""); +#endif + return true; +} + +inline bool strncmp_PP(const char *p1, const char *p2, uint8_t n) +{ + for (; n > 0; -- n, ++ p1, ++ p2) { + if (pgm_read_byte(p1) < pgm_read_byte(p2)) + return -1; + if (pgm_read_byte(p1) > pgm_read_byte(p2)) + return 1; + if (pgm_read_byte(p1) == 0) + return 0; + } + return 0; +} + +// Parse a major.minor.revision version number. +// Return true if valid. +inline bool parse_version_P(const char *str, uint16_t version[4]) +{ +#if 0 + SERIAL_ECHOPGM("Parsing version string "); + SERIAL_ECHORPGM(str); + SERIAL_ECHOLNPGM(""); +#endif + + const char *major = str; + const char *p = str; + while (is_digit(char(pgm_read_byte(p)))) ++ p; + if (pgm_read_byte(p) != '.') + return false; + const char *minor = ++ p; + while (is_digit(char(pgm_read_byte(p)))) ++ p; + if (pgm_read_byte(p) != '.') + return false; + const char *rev = ++ p; + while (is_digit(char(pgm_read_byte(p)))) ++ p; + if (! is_whitespace_or_nl_or_eol(char(pgm_read_byte(p))) && pgm_read_byte(p) != '-') + return false; + + char buf[5]; + uint8_t n = minor - major - 1; + if (n > 4) + return false; + memcpy_P(buf, major, n); buf[n] = 0; + char *endptr = NULL; + version[0] = strtol(buf, &endptr, 10); + if (*endptr != 0) + return false; + n = rev - minor - 1; + if (n > 4) + return false; + memcpy_P(buf, minor, n); buf[n] = 0; + version[1] = strtol(buf, &endptr, 10); + if (*endptr != 0) + return false; + n = p - rev; + if (n > 4) + return false; + memcpy_P(buf, rev, n); + buf[n] = 0; + version[2] = strtol(buf, &endptr, 10); + if (*endptr != 0) + return false; + + version[3] = FIRMWARE_REVISION_RELEASED; + if (pgm_read_byte(p ++) == '-') { + const char *q = p; + while (! is_whitespace_or_nl_or_eol(char(pgm_read_byte(q)))) + ++ q; + n = q - p; + if (n == strlen_P(STR_REVISION_DEV) && strncmp_PP(p, STR_REVISION_DEV, n) == 0) + version[3] = FIRMWARE_REVISION_DEV; + else if (n == strlen_P(STR_REVISION_ALPHA) && strncmp_PP(p, STR_REVISION_ALPHA, n) == 0) + version[3] = FIRMWARE_REVISION_ALPHA; + else if (n == strlen_P(STR_REVISION_BETA) && strncmp_PP(p, STR_REVISION_BETA, n) == 0) + version[3] = FIRMWARE_REVISION_BETA; + else if ((n == 2 || n == 3) && strncmp_PP(p, STR_REVISION_RC, 2) == 0) { + if (n == 2) + version[3] = FIRMWARE_REVISION_RC; + else { + p += 2; + if (is_digit(pgm_read_byte(p))) + version[3] = FIRMWARE_REVISION_RC + pgm_read_byte(p) - '1'; + else + return false; + } + } else + return false; + } + +#if 0 + SERIAL_ECHOPGM("Version parsed, major: "); + SERIAL_ECHO(version[0]); + SERIAL_ECHOPGM(", minor: "); + SERIAL_ECHO(version[1]); + SERIAL_ECHOPGM(", revision: "); + SERIAL_ECHO(version[2]); + SERIAL_ECHOPGM(", flavor: "); + SERIAL_ECHO(version[3]); + SERIAL_ECHOLNPGM(""); +#endif + return true; +} + +// 1 - yes, 0 - false, -1 - error; +inline int8_t is_provided_version_newer(const char *version_string) +{ + uint16_t ver_gcode[3], ver_current[3]; + if (! parse_version(version_string, ver_gcode)) + return -1; + if (! parse_version_P(FW_VERSION_STR, ver_current)) + return 0; // this shall not happen + for (uint8_t i = 0; i < 3; ++ i) + if (ver_gcode[i] > ver_current[i]) + return 1; + return 0; +} + +bool show_upgrade_dialog_if_version_newer(const char *version_string) +{ + uint16_t ver_gcode[4], ver_current[4]; + if (! parse_version(version_string, ver_gcode)) { +// SERIAL_PROTOCOLLNPGM("parse_version failed"); + return false; + } + if (! parse_version_P(FW_VERSION_STR, ver_current)) { +// SERIAL_PROTOCOLLNPGM("parse_version_P failed"); + return false; // this shall not happen + } +// SERIAL_PROTOCOLLNPGM("versions parsed"); + bool upgrade = false; + for (uint8_t i = 0; i < 4; ++ i) { + if (ver_gcode[i] > ver_current[i]) { + upgrade = true; + break; + } else if (ver_gcode[i] < ver_current[i]) + break; + } + + if (upgrade) { + lcd_display_message_fullscreen_P(MSG_NEW_FIRMWARE_AVAILABLE); + lcd_print_at_PGM(0, 2, PSTR("")); + for (const char *c = version_string; ! is_whitespace_or_nl_or_eol(*c); ++ c) + lcd_implementation_write(*c); + lcd_print_at_PGM(0, 3, MSG_NEW_FIRMWARE_PLEASE_UPGRADE); + tone(BEEPER, 1000); + delay_keep_alive(50); + noTone(BEEPER); + delay_keep_alive(500); + tone(BEEPER, 1000); + delay_keep_alive(50); + noTone(BEEPER); + lcd_wait_for_click(); + lcd_update_enable(true); + lcd_implementation_clear(); + lcd_update(); + } + + // Succeeded. + return true; +} + +void update_current_firmware_version_to_eeprom() +{ + for (int8_t i = 0; i < FW_PRUSA3D_MAGIC_LEN; ++ i) + eeprom_update_byte((uint8_t*)(EEPROM_FIRMWARE_PRUSA_MAGIC+i), pgm_read_byte(FW_PRUSA3D_MAGIC_STR+i)); + uint16_t ver_current[4]; + if (parse_version_P(FW_VERSION_STR, ver_current)) { + eeprom_update_word((uint16_t*)EEPROM_FIRMWARE_VERSION_MAJOR, ver_current[0]); + eeprom_update_word((uint16_t*)EEPROM_FIRMWARE_VERSION_MINOR, ver_current[1]); + eeprom_update_word((uint16_t*)EEPROM_FIRMWARE_VERSION_REVISION, ver_current[2]); + // See FirmwareRevisionFlavorType for the definition of firmware flavors. + eeprom_update_word((uint16_t*)EEPROM_FIRMWARE_VERSION_FLAVOR, ver_current[3]); + } +} diff --git a/Firmware/util.h b/Firmware/util.h index d740aaf44..52e4b6bce 100644 --- a/Firmware/util.h +++ b/Firmware/util.h @@ -1,35 +1,35 @@ -#ifndef UTIL_H -#define UTIL_H - -extern const char* FW_VERSION_STR_P(); - -// Definition of a firmware flavor numerical values. -enum FirmwareRevisionFlavorType -{ - FIRMWARE_REVISION_DEV = 0, - FIRMWARE_REVISION_ALPHA = 1, - FIRMWARE_REVISION_BETA = 2, - FIRMWARE_REVISION_RC, - FIRMWARE_REVISION_RC2, - FIRMWARE_REVISION_RC3, - FIRMWARE_REVISION_RC4, - FIRMWARE_REVISION_RC5, - FIRMWARE_REVISION_RELEASED = 127 -}; - -extern bool show_upgrade_dialog_if_version_newer(const char *version_string); - -extern void update_current_firmware_version_to_eeprom(); - - - -inline int8_t eeprom_read_int8(unsigned char* addr) { - uint8_t v = eeprom_read_byte(addr); - return *reinterpret_cast(&v); -} - -inline void eeprom_update_int8(unsigned char* addr, int8_t v) { - eeprom_update_byte(addr, *reinterpret_cast(&v)); -} - -#endif /* UTIL_H */ +#ifndef UTIL_H +#define UTIL_H + +extern const char* FW_VERSION_STR_P(); + +// Definition of a firmware flavor numerical values. +enum FirmwareRevisionFlavorType +{ + FIRMWARE_REVISION_DEV = 0, + FIRMWARE_REVISION_ALPHA = 1, + FIRMWARE_REVISION_BETA = 2, + FIRMWARE_REVISION_RC, + FIRMWARE_REVISION_RC2, + FIRMWARE_REVISION_RC3, + FIRMWARE_REVISION_RC4, + FIRMWARE_REVISION_RC5, + FIRMWARE_REVISION_RELEASED = 127 +}; + +extern bool show_upgrade_dialog_if_version_newer(const char *version_string); + +extern void update_current_firmware_version_to_eeprom(); + + + +inline int8_t eeprom_read_int8(unsigned char* addr) { + uint8_t v = eeprom_read_byte(addr); + return *reinterpret_cast(&v); +} + +inline void eeprom_update_int8(unsigned char* addr, int8_t v) { + eeprom_update_byte(addr, *reinterpret_cast(&v)); +} + +#endif /* UTIL_H */ diff --git a/Firmware/variants/1_75mm_MK2-EINY01-E3Dv6full.h b/Firmware/variants/1_75mm_MK2-EINY01-E3Dv6full.h index 0bd7ad650..de326edee 100644 --- a/Firmware/variants/1_75mm_MK2-EINY01-E3Dv6full.h +++ b/Firmware/variants/1_75mm_MK2-EINY01-E3Dv6full.h @@ -17,7 +17,15 @@ // Electronics #define MOTHERBOARD BOARD_EINY_0_1a -//#define MOTHERBOARD BOARD_RAMBO_MINI_1_0 + + + +// Uncomment the below for the E3D PT100 temperature sensor (with or without PT100 Amplifier) +//#define E3D_PT100_EXTRUDER_WITH_AMP +//#define E3D_PT100_EXTRUDER_NO_AMP +//#define E3D_PT100_BED_WITH_AMP +//#define E3D_PT100_BED_NO_AMP + /*------------------------------------ AXIS SETTINGS @@ -48,6 +56,11 @@ const bool Z_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic o #define X_CANCEL_POS 50 #define Y_CANCEL_POS 190 +//Pause print position +#define X_PAUSE_POS 50 +#define Y_PAUSE_POS 190 +#define Z_PAUSE_LIFT 20 + #define NUM_AXIS 4 // The axis order in all axis related arrays is X, Y, Z, E #define HOMING_FEEDRATE {3000, 3000, 800, 0} // set the homing speeds (mm/min) // 3000 is also valid for stallGuard homing. Valid range: 2200 - 3000 @@ -86,6 +99,30 @@ const bool Z_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic o #define TMC_DEBUG +// PWM register configuration +#define PWM_GRAD 0x08 // 0x0F - Sets gradient - (max 15 with PWM autoscale activated) +#define PWM_AMPL 0xC8 // 0xFF - Sets PWM amplitude to 200 (max is 255) +#define PWM_AUTOSCALE 0x04 // 0x04 since writing in PWM_CONF (Activates PWM autoscaling) +#define PWM_FREQ 0x01 // 0x01 since writing in PWM_CONF (Sets PWM frequency to 2/683 fCLK) + +// Special configuration for XY axes for operation (during standstill, use same settings as for other axes) //todo +#define PWM_GRAD_XY 156 // 0x0F - Sets gradient - (max 15 with PWM autoscale activated) +#define PWM_AMPL_XY 63 // 0xFF - Sets PWM amplitude to 200 (max is 255) +#define PWM_AUTOSCALE_XY 0x00 // 0x04 since writing in PWM_CONF (Activates PWM autoscaling) +#define PWM_FREQ_XY 0x01 // 0x01 since writing in PWM_CONF (Sets PWM frequency to 2/683 fCLK) + +#define PWM_THRS 0x00 // TPWM_THRS - Sets the switching speed threshold based on TSTEP from stealthChop to spreadCycle mode + +#define SG_HOMING 1 +#define SG_THRESHOLD_X 8 +#define SG_THRESHOLD_Y 8 +#define TCOOLTHRS 239 + +#define TMC_DEBUG +//#define TMC_DBG_READS +//#define TMC_DBG_WRITE + + /*------------------------------------ EXTRUDER SETTINGS *------------------------------------*/ @@ -97,15 +134,26 @@ const bool Z_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic o #define BED_MINTEMP 15 // Maxtemps +#if defined(E3D_PT100_EXTRUDER_WITH_AMP) || defined(E3D_PT100_EXTRUDER_NO_AMP) +#define HEATER_0_MAXTEMP 410 +#else #define HEATER_0_MAXTEMP 305 +#endif #define HEATER_1_MAXTEMP 305 #define HEATER_2_MAXTEMP 305 #define BED_MAXTEMP 150 +#if defined(E3D_PT100_EXTRUDER_WITH_AMP) || defined(E3D_PT100_EXTRUDER_NO_AMP) +// Define PID constants for extruder with PT100 +#define DEFAULT_Kp 21.70 +#define DEFAULT_Ki 1.60 +#define DEFAULT_Kd 73.76 +#else // Define PID constants for extruder #define DEFAULT_Kp 40.925 #define DEFAULT_Ki 4.875 #define DEFAULT_Kd 86.085 +#endif // Extrude mintemp #define EXTRUDE_MINTEMP 130 @@ -214,7 +262,7 @@ const bool Z_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic o #define MESH_MEAS_NUM_Y_POINTS 3 #define MESH_HOME_Z_CALIB 0.2 -#define MESH_HOME_Z_SEARCH 5 +#define MESH_HOME_Z_SEARCH 5 //Z lift for homing, mesh bed leveling etc. #define X_PROBE_OFFSET_FROM_EXTRUDER 23 // Z probe to nozzle X offset: -left +right #define Y_PROBE_OFFSET_FROM_EXTRUDER 9 // Z probe to nozzle Y offset: -front +behind @@ -250,9 +298,16 @@ const bool Z_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic o #ifdef PIDTEMPBED //120v 250W silicone heater into 4mm borosilicate (MendelMax 1.5+) //from FOPDT model - kp=.39 Tp=405 Tdead=66, Tc set to 79.2, aggressive factor of .15 (vs .1, 1, 10) +#if defined(E3D_PT100_BED_WITH_AMP) || defined(E3D_PT100_BED_NO_AMP) +// Define PID constants for extruder with PT100 +#define DEFAULT_bedKp 21.70 +#define DEFAULT_bedKi 1.60 +#define DEFAULT_bedKd 73.76 +#else #define DEFAULT_bedKp 126.13 #define DEFAULT_bedKi 4.30 #define DEFAULT_bedKd 924.76 +#endif //120v 250W silicone heater into 4mm borosilicate (MendelMax 1.5+) //from pidautotune @@ -329,12 +384,26 @@ const bool Z_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic o // 1047 is Pt1000 with 4k7 pullup // 1010 is Pt1000 with 1k pullup (non standard) // 147 is Pt100 with 4k7 pullup +// 148 is E3D Pt100 with 4k7 pullup and no PT100 Amplifier on a MiniRambo 1.3a +// 247 is Pt100 with 4k7 pullup and PT100 Amplifier // 110 is Pt100 with 1k pullup (non standard) +#if defined(E3D_PT100_EXTRUDER_WITH_AMP) +#define TEMP_SENSOR_0 247 +#elif defined(E3D_PT100_EXTRUDER_NO_AMP) +#define TEMP_SENSOR_0 148 +#else #define TEMP_SENSOR_0 5 +#endif #define TEMP_SENSOR_1 0 #define TEMP_SENSOR_2 0 +#if defined(E3D_PT100_BED_WITH_AMP) +#define TEMP_SENSOR_BED 247 +#elif defined(E3D_PT100_BED_NO_AMP) +#define TEMP_SENSOR_BED 148 +#else #define TEMP_SENSOR_BED 1 +#endif #define STACK_GUARD_TEST_VALUE 0xA2A2 @@ -344,16 +413,33 @@ const bool Z_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic o #define MAX_E_STEPS_PER_UNIT 250 #define MIN_E_STEPS_PER_UNIT 100 -#define PRINT_STARTED 0xFE -#define PRINT_FINISHED 0xFF - #define Z_BABYSTEP_MIN -3999 #define Z_BABYSTEP_MAX 0 +#define PINDA_PREHEAT_X 70 +#define PINDA_PREHEAT_Y -3 +#define PINDA_PREHEAT_Z 1 +#define PINDA_HEAT_T 120 //time in s + +#define PINDA_MIN_T 50 +#define PINDA_STEP_T 10 +#define PINDA_MAX_T 100 + #define PING_TIME 60 //time in s #define PING_TIME_LONG 600 //10 min; used when length of commands buffer > 0 to avoid false triggering when dealing with long gcodes #define PING_ALLERT_PERIOD 60 //time in s #define LONG_PRESS_TIME 1000 //time in ms for button long press +#define BUTTON_BLANKING_TIME 200 //time in ms for blanking after button release + +#define DEFAULT_PID_TEMP 210 + +#define MIN_PRINT_FAN_SPEED 50 + +#ifdef SNMM +#define DEFAULT_RETRACTION 4 //used for PINDA temp calibration and pause print +#else +#define DEFAULT_RETRACTION 1 //used for PINDA temp calibration and pause print +#endif #endif //__CONFIGURATION_PRUSA_H diff --git a/Firmware/variants/1_75mm_MK2-RAMBo10a-E3Dv6full.h b/Firmware/variants/1_75mm_MK2-RAMBo10a-E3Dv6full.h index 23d612d38..d7019845f 100644 --- a/Firmware/variants/1_75mm_MK2-RAMBo10a-E3Dv6full.h +++ b/Firmware/variants/1_75mm_MK2-RAMBo10a-E3Dv6full.h @@ -18,13 +18,27 @@ GENERAL SETTINGS // Electronics #define MOTHERBOARD BOARD_RAMBO_MINI_1_0 +// Prusa Single extruder multiple material suport +//#define SNMM + +// Uncomment the below for the E3D PT100 temperature sensor (with or without PT100 Amplifier) +//#define E3D_PT100_EXTRUDER_WITH_AMP +//#define E3D_PT100_EXTRUDER_NO_AMP +//#define E3D_PT100_BED_WITH_AMP +//#define E3D_PT100_BED_NO_AMP + /*------------------------------------ AXIS SETTINGS *------------------------------------*/ // Steps per unit {X,Y,Z,E} +#ifdef SNMM +#define DEFAULT_AXIS_STEPS_PER_UNIT {100,100,3200/8,140} +#else #define DEFAULT_AXIS_STEPS_PER_UNIT {100,100,3200/8,161.3} +#endif + // Endstop inverting const bool X_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic of the endstop. @@ -48,6 +62,11 @@ const bool Z_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic o #define X_CANCEL_POS 50 #define Y_CANCEL_POS 190 +//Pause print position +#define X_PAUSE_POS 50 +#define Y_PAUSE_POS 190 +#define Z_PAUSE_LIFT 20 + #define NUM_AXIS 4 // The axis order in all axis related arrays is X, Y, Z, E #define HOMING_FEEDRATE {3000, 3000, 800, 0} // set the homing speeds (mm/min) @@ -73,15 +92,26 @@ EXTRUDER SETTINGS #define BED_MINTEMP 15 // Maxtemps +#if defined(E3D_PT100_EXTRUDER_WITH_AMP) || defined(E3D_PT100_EXTRUDER_NO_AMP) +#define HEATER_0_MAXTEMP 410 +#else #define HEATER_0_MAXTEMP 305 +#endif #define HEATER_1_MAXTEMP 305 #define HEATER_2_MAXTEMP 305 #define BED_MAXTEMP 150 +#if defined(E3D_PT100_EXTRUDER_WITH_AMP) || defined(E3D_PT100_EXTRUDER_NO_AMP) +// Define PID constants for extruder with PT100 +#define DEFAULT_Kp 21.70 +#define DEFAULT_Ki 1.60 +#define DEFAULT_Kd 73.76 +#else // Define PID constants for extruder #define DEFAULT_Kp 40.925 #define DEFAULT_Ki 4.875 #define DEFAULT_Kd 86.085 +#endif // Extrude mintemp #define EXTRUDE_MINTEMP 130 @@ -98,13 +128,15 @@ EXTRUDER SETTINGS #ifdef SNMM //#define BOWDEN_LENGTH 408 -#define BOWDEN_LENGTH 457 //total length for filament fast loading part; max length for extrusion is 465 mm! +#define BOWDEN_LENGTH 433 //default total length for filament fast loading part; max length for extrusion is 465 mm!; this length can be adjusted in service menu #define FIL_LOAD_LENGTH 102 //length for loading filament into the nozzle -#define FIL_RETURN_LENGTH 30.5 //for filament adjusting (PRUSAY code) +#define FIL_COOLING 10 //length for cooling moves #define E_MOTOR_LOW_CURRENT 350 // current for PRUSAY code #define E_MOTOR_HIGH_CURRENT 700 //current for unloading filament, stop print, PRUSAY ramming +#endif //SNMM + +//#define DIS //for measuring bed heigth and PINDa detection heigth relative to auto home point, experimental function -#endif /*------------------------------------ CHANGE FILAMENT SETTINGS @@ -143,8 +175,8 @@ ADDITIONAL FEATURES SETTINGS #endif // temperature runaway -//#define TEMP_RUNAWAY_BED_HYSTERESIS 5 -//#define TEMP_RUNAWAY_BED_TIMEOUT 360 +#define TEMP_RUNAWAY_BED_HYSTERESIS 5 +#define TEMP_RUNAWAY_BED_TIMEOUT 360 #define TEMP_RUNAWAY_EXTRUDER_HYSTERESIS 15 #define TEMP_RUNAWAY_EXTRUDER_TIMEOUT 45 @@ -188,7 +220,7 @@ BED SETTINGS #define MESH_MEAS_NUM_Y_POINTS 3 #define MESH_HOME_Z_CALIB 0.2 -#define MESH_HOME_Z_SEARCH 5 +#define MESH_HOME_Z_SEARCH 5 //Z lift for homing, mesh bed leveling etc. #define X_PROBE_OFFSET_FROM_EXTRUDER 23 // Z probe to nozzle X offset: -left +right #define Y_PROBE_OFFSET_FROM_EXTRUDER 9 // Z probe to nozzle Y offset: -front +behind @@ -224,9 +256,16 @@ BED SETTINGS #ifdef PIDTEMPBED //120v 250W silicone heater into 4mm borosilicate (MendelMax 1.5+) //from FOPDT model - kp=.39 Tp=405 Tdead=66, Tc set to 79.2, aggressive factor of .15 (vs .1, 1, 10) +#if defined(E3D_PT100_BED_WITH_AMP) || defined(E3D_PT100_BED_NO_AMP) +// Define PID constants for extruder with PT100 +#define DEFAULT_bedKp 21.70 +#define DEFAULT_bedKi 1.60 +#define DEFAULT_bedKd 73.76 +#else #define DEFAULT_bedKp 126.13 #define DEFAULT_bedKi 4.30 #define DEFAULT_bedKd 924.76 +#endif //120v 250W silicone heater into 4mm borosilicate (MendelMax 1.5+) //from pidautotune @@ -303,12 +342,26 @@ THERMISTORS SETTINGS // 1047 is Pt1000 with 4k7 pullup // 1010 is Pt1000 with 1k pullup (non standard) // 147 is Pt100 with 4k7 pullup +// 148 is Pt100 with 4k7 pullup and no PT100 Amplifier (in case type 147 doesn't work) +// 247 is Pt100 with 4k7 pullup and PT100 Amplifier // 110 is Pt100 with 1k pullup (non standard) +#if defined(E3D_PT100_EXTRUDER_WITH_AMP) +#define TEMP_SENSOR_0 247 +#elif defined(E3D_PT100_EXTRUDER_NO_AMP) +#define TEMP_SENSOR_0 148 +#else #define TEMP_SENSOR_0 5 +#endif #define TEMP_SENSOR_1 0 #define TEMP_SENSOR_2 0 +#if defined(E3D_PT100_BED_WITH_AMP) +#define TEMP_SENSOR_BED 247 +#elif defined(E3D_PT100_BED_NO_AMP) +#define TEMP_SENSOR_BED 148 +#else #define TEMP_SENSOR_BED 1 +#endif #define STACK_GUARD_TEST_VALUE 0xA2A2 @@ -318,16 +371,31 @@ THERMISTORS SETTINGS #define MAX_E_STEPS_PER_UNIT 250 #define MIN_E_STEPS_PER_UNIT 100 -#define PRINT_STARTED 0xFE -#define PRINT_FINISHED 0xFF - #define Z_BABYSTEP_MIN -3999 #define Z_BABYSTEP_MAX 0 +#define PINDA_PREHEAT_X 70 +#define PINDA_PREHEAT_Y -3 +#define PINDA_PREHEAT_Z 1 +#define PINDA_HEAT_T 120 //time in s + +#define PINDA_MIN_T 50 +#define PINDA_STEP_T 10 +#define PINDA_MAX_T 100 + #define PING_TIME 60 //time in s #define PING_TIME_LONG 600 //10 min; used when length of commands buffer > 0 to avoid false triggering when dealing with long gcodes #define PING_ALLERT_PERIOD 60 //time in s -#define LONG_PRESS_TIME 1000 //time in ms for button long press +#define LONG_PRESS_TIME 1000 //time in ms for button long press +#define BUTTON_BLANKING_TIME 200 //time in ms for blanking after button release + +#define DEFAULT_PID_TEMP 210 + +#ifdef SNMM +#define DEFAULT_RETRACTION 4 //used for PINDA temp calibration and pause print +#else +#define DEFAULT_RETRACTION 1 //used for PINDA temp calibration and pause print +#endif #endif //__CONFIGURATION_PRUSA_H diff --git a/Firmware/variants/1_75mm_MK2-RAMBo13a-E3Dv6full.h b/Firmware/variants/1_75mm_MK2-RAMBo13a-E3Dv6full.h index 852d2c620..720e74f5e 100644 --- a/Firmware/variants/1_75mm_MK2-RAMBo13a-E3Dv6full.h +++ b/Firmware/variants/1_75mm_MK2-RAMBo13a-E3Dv6full.h @@ -18,13 +18,27 @@ GENERAL SETTINGS // Electronics #define MOTHERBOARD BOARD_RAMBO_MINI_1_3 +// Prusa Single extruder multiple material suport +//#define SNMM + +// Uncomment the below for the E3D PT100 temperature sensor (with or without PT100 Amplifier) +//#define E3D_PT100_EXTRUDER_WITH_AMP +//#define E3D_PT100_EXTRUDER_NO_AMP +//#define E3D_PT100_BED_WITH_AMP +//#define E3D_PT100_BED_NO_AMP + /*------------------------------------ AXIS SETTINGS *------------------------------------*/ // Steps per unit {X,Y,Z,E} +#ifdef SNMM +#define DEFAULT_AXIS_STEPS_PER_UNIT {100,100,3200/8,140} +#else #define DEFAULT_AXIS_STEPS_PER_UNIT {100,100,3200/8,161.3} +#endif + // Endstop inverting const bool X_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic of the endstop. @@ -48,6 +62,11 @@ const bool Z_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic o #define X_CANCEL_POS 50 #define Y_CANCEL_POS 190 +//Pause print position +#define X_PAUSE_POS 50 +#define Y_PAUSE_POS 190 +#define Z_PAUSE_LIFT 20 + #define NUM_AXIS 4 // The axis order in all axis related arrays is X, Y, Z, E #define HOMING_FEEDRATE {3000, 3000, 800, 0} // set the homing speeds (mm/min) @@ -73,15 +92,26 @@ EXTRUDER SETTINGS #define BED_MINTEMP 15 // Maxtemps +#if defined(E3D_PT100_EXTRUDER_WITH_AMP) || defined(E3D_PT100_EXTRUDER_NO_AMP) +#define HEATER_0_MAXTEMP 410 +#else #define HEATER_0_MAXTEMP 305 +#endif #define HEATER_1_MAXTEMP 305 #define HEATER_2_MAXTEMP 305 #define BED_MAXTEMP 150 +#if defined(E3D_PT100_EXTRUDER_WITH_AMP) || defined(E3D_PT100_EXTRUDER_NO_AMP) +// Define PID constants for extruder with PT100 +#define DEFAULT_Kp 21.70 +#define DEFAULT_Ki 1.60 +#define DEFAULT_Kd 73.76 +#else // Define PID constants for extruder #define DEFAULT_Kp 40.925 #define DEFAULT_Ki 4.875 #define DEFAULT_Kd 86.085 +#endif // Extrude mintemp #define EXTRUDE_MINTEMP 130 @@ -93,18 +123,22 @@ EXTRUDER SETTINGS #define EXTRUDER_AUTO_FAN_TEMPERATURE 50 #define EXTRUDER_AUTO_FAN_SPEED 255 // == full speed -// Prusa Single extruder multiple material suport -//#define SNMM + + + + #ifdef SNMM //#define BOWDEN_LENGTH 408 -#define BOWDEN_LENGTH 457 //total length for filament fast loading part; max length for extrusion is 465 mm! +#define BOWDEN_LENGTH 433 //default total length for filament fast loading part; max length for extrusion is 465 mm!; this length can be adjusted in service menu #define FIL_LOAD_LENGTH 102 //length for loading filament into the nozzle -#define FIL_RETURN_LENGTH 30.5 //for filament adjusting (PRUSAY code) +#define FIL_COOLING 10 //length for cooling moves #define E_MOTOR_LOW_CURRENT 350 // current for PRUSAY code #define E_MOTOR_HIGH_CURRENT 700 //current for unloading filament, stop print, PRUSAY ramming +#endif //SNMM + +//#define DIS //for measuring bed heigth and PINDa detection heigth relative to auto home point, experimental function -#endif /*------------------------------------ CHANGE FILAMENT SETTINGS @@ -143,8 +177,8 @@ ADDITIONAL FEATURES SETTINGS #endif // temperature runaway -//#define TEMP_RUNAWAY_BED_HYSTERESIS 5 -//#define TEMP_RUNAWAY_BED_TIMEOUT 360 +#define TEMP_RUNAWAY_BED_HYSTERESIS 5 +#define TEMP_RUNAWAY_BED_TIMEOUT 360 #define TEMP_RUNAWAY_EXTRUDER_HYSTERESIS 15 #define TEMP_RUNAWAY_EXTRUDER_TIMEOUT 45 @@ -188,7 +222,7 @@ BED SETTINGS #define MESH_MEAS_NUM_Y_POINTS 3 #define MESH_HOME_Z_CALIB 0.2 -#define MESH_HOME_Z_SEARCH 5 +#define MESH_HOME_Z_SEARCH 5 //Z lift for homing, mesh bed leveling etc. #define X_PROBE_OFFSET_FROM_EXTRUDER 23 // Z probe to nozzle X offset: -left +right #define Y_PROBE_OFFSET_FROM_EXTRUDER 9 // Z probe to nozzle Y offset: -front +behind @@ -224,9 +258,16 @@ BED SETTINGS #ifdef PIDTEMPBED //120v 250W silicone heater into 4mm borosilicate (MendelMax 1.5+) //from FOPDT model - kp=.39 Tp=405 Tdead=66, Tc set to 79.2, aggressive factor of .15 (vs .1, 1, 10) +#if defined(E3D_PT100_BED_WITH_AMP) || defined(E3D_PT100_BED_NO_AMP) +// Define PID constants for extruder with PT100 +#define DEFAULT_bedKp 21.70 +#define DEFAULT_bedKi 1.60 +#define DEFAULT_bedKd 73.76 +#else #define DEFAULT_bedKp 126.13 #define DEFAULT_bedKi 4.30 #define DEFAULT_bedKd 924.76 +#endif //120v 250W silicone heater into 4mm borosilicate (MendelMax 1.5+) //from pidautotune @@ -303,12 +344,26 @@ THERMISTORS SETTINGS // 1047 is Pt1000 with 4k7 pullup // 1010 is Pt1000 with 1k pullup (non standard) // 147 is Pt100 with 4k7 pullup +// 148 is E3D Pt100 with 4k7 pullup and no PT100 Amplifier on a MiniRambo 1.3a +// 247 is Pt100 with 4k7 pullup and PT100 Amplifier // 110 is Pt100 with 1k pullup (non standard) +#if defined(E3D_PT100_EXTRUDER_WITH_AMP) +#define TEMP_SENSOR_0 247 +#elif defined(E3D_PT100_EXTRUDER_NO_AMP) +#define TEMP_SENSOR_0 148 +#else #define TEMP_SENSOR_0 5 +#endif #define TEMP_SENSOR_1 0 #define TEMP_SENSOR_2 0 +#if defined(E3D_PT100_BED_WITH_AMP) +#define TEMP_SENSOR_BED 247 +#elif defined(E3D_PT100_BED_NO_AMP) +#define TEMP_SENSOR_BED 148 +#else #define TEMP_SENSOR_BED 1 +#endif #define STACK_GUARD_TEST_VALUE 0xA2A2 @@ -318,16 +373,31 @@ THERMISTORS SETTINGS #define MAX_E_STEPS_PER_UNIT 250 #define MIN_E_STEPS_PER_UNIT 100 -#define PRINT_STARTED 0xFE -#define PRINT_FINISHED 0xFF - #define Z_BABYSTEP_MIN -3999 #define Z_BABYSTEP_MAX 0 +#define PINDA_PREHEAT_X 70 +#define PINDA_PREHEAT_Y -3 +#define PINDA_PREHEAT_Z 1 +#define PINDA_HEAT_T 120 //time in s + +#define PINDA_MIN_T 50 +#define PINDA_STEP_T 10 +#define PINDA_MAX_T 100 + #define PING_TIME 60 //time in s #define PING_TIME_LONG 600 //10 min; used when length of commands buffer > 0 to avoid false triggering when dealing with long gcodes #define PING_ALLERT_PERIOD 60 //time in s -#define LONG_PRESS_TIME 1000 //time in ms for button long press +#define LONG_PRESS_TIME 1000 //time in ms for button long press +#define BUTTON_BLANKING_TIME 200 //time in ms for blanking after button release + +#define DEFAULT_PID_TEMP 210 + +#ifdef SNMM +#define DEFAULT_RETRACTION 4 //used for PINDA temp calibration and pause print +#else +#define DEFAULT_RETRACTION 1 //used for PINDA temp calibration and pause print +#endif #endif //__CONFIGURATION_PRUSA_H