Firmware2/Marlin/src/module/configuration_store.cpp

3465 lines
99 KiB
C++
Raw Normal View History

/**
2016-03-24 19:01:20 +01:00
* Marlin 3D Printer Firmware
2019-06-28 06:57:50 +02:00
* Copyright (c) 2019 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
2016-03-24 19:01:20 +01:00
*
* Based on Sprinter and grbl.
2019-06-28 06:57:50 +02:00
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
2016-03-24 19:01:20 +01:00
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
/**
2015-04-26 06:04:54 +02:00
* configuration_store.cpp
*
2017-04-10 04:47:49 +02:00
* Settings and EEPROM storage
*
2015-04-04 01:38:05 +02:00
* IMPORTANT: Whenever there are changes made to the variables stored in EEPROM
* in the functions below, also increment the version number. This makes sure that
* the default values are used whenever there is a change to the data, to prevent
* wrong data being written to the variables.
*
* ALSO: Variables in the Store and Retrieve sections must be in the same order.
* If a feature is disabled, some data must still be written that, when read,
* either sets a Sane Default, or results in No Change to the existing value.
*
*/
2018-01-05 02:59:43 +01:00
// Change EEPROM version if the structure changes
#define EEPROM_VERSION "V74"
#define EEPROM_OFFSET 100
2018-01-05 03:27:17 +01:00
// Check the integrity of data offsets.
// Can be disabled for production build.
//#define DEBUG_EEPROM_READWRITE
2017-04-10 04:47:49 +02:00
#include "configuration_store.h"
2018-03-15 04:44:07 +01:00
#include "endstops.h"
#include "planner.h"
#include "stepper.h"
2017-09-06 13:28:32 +02:00
#include "temperature.h"
#include "../lcd/ultralcd.h"
#include "../core/language.h"
2019-09-29 11:25:39 +02:00
#include "../libs/vector_3.h" // for matrix_3x3
2018-01-05 02:59:43 +01:00
#include "../gcode/gcode.h"
2017-09-06 13:28:32 +02:00
#include "../Marlin.h"
#if EITHER(EEPROM_SETTINGS, SD_FIRMWARE_UPDATE)
#include "../HAL/shared/persistent_store_api.h"
#endif
2019-09-25 04:29:21 +02:00
#include "probe.h"
2017-09-08 22:35:25 +02:00
#if HAS_LEVELING
#include "../feature/bedlevel/bedlevel.h"
#endif
#if ENABLED(EXTENSIBLE_UI)
#include "../lcd/extensible_ui/ui_api.h"
#endif
2018-08-07 17:04:46 +02:00
#if HAS_SERVOS
#include "servo.h"
#endif
#if HAS_SERVOS && HAS_SERVO_ANGLES
#define EEPROM_NUM_SERVOS NUM_SERVOS
#else
#define EEPROM_NUM_SERVOS NUM_SERVO_PLUGS
2018-08-25 04:53:42 +02:00
#endif
2018-08-07 17:04:46 +02:00
2018-10-20 23:10:50 +02:00
#include "../feature/fwretract.h"
2018-11-17 03:47:07 +01:00
#if ENABLED(POWER_LOSS_RECOVERY)
#include "../feature/power_loss_recovery.h"
#endif
2018-10-20 23:10:50 +02:00
#include "../feature/pause.h"
2018-02-22 19:28:46 +01:00
#if ENABLED(BACKLASH_COMPENSATION)
#include "../feature/backlash.h"
#endif
#if HAS_FILAMENT_SENSOR
#include "../feature/runout.h"
#endif
#if ENABLED(EXTRA_LIN_ADVANCE_K)
2019-07-28 05:44:05 +02:00
extern float saved_extruder_advance_K[EXTRUDERS];
#endif
#if EXTRUDERS > 1
2018-10-08 00:06:14 +02:00
#include "tool_change.h"
void M217_report(const bool eeprom);
#endif
2019-05-26 04:56:47 +02:00
#if ENABLED(BLTOUCH)
#include "../feature/bltouch.h"
#endif
#if HAS_TRINAMIC
2019-09-01 02:44:45 +02:00
#include "stepper/indirection.h"
#include "../feature/tmc_util.h"
#endif
#pragma pack(push, 1) // No padding between variables
typedef struct { uint16_t X, Y, Z, X2, Y2, Z2, Z3, E0, E1, E2, E3, E4, E5; } tmc_stepper_current_t;
typedef struct { uint32_t X, Y, Z, X2, Y2, Z2, Z3, E0, E1, E2, E3, E4, E5; } tmc_hybrid_threshold_t;
typedef struct { int16_t X, Y, Z, X2; } tmc_sgt_t;
typedef struct { bool X, Y, Z, X2, Y2, Z2, Z3, E0, E1, E2, E3, E4, E5; } tmc_stealth_enabled_t;
// Limit an index to an array size
#define ALIM(I,ARR) _MIN(I, COUNT(ARR) - 1)
2018-01-05 02:59:43 +01:00
2019-09-26 08:28:09 +02:00
// Defaults for reset / fill in on load
static const uint32_t _DMA[] PROGMEM = DEFAULT_MAX_ACCELERATION;
static const float _DASU[] PROGMEM = DEFAULT_AXIS_STEPS_PER_UNIT;
static const feedRate_t _DMF[] PROGMEM = DEFAULT_MAX_FEEDRATE;
extern const char SP_X_STR[], SP_Y_STR[], SP_Z_STR[], SP_E_STR[];
2018-01-05 02:59:43 +01:00
/**
* Current EEPROM Layout
*
* Keep this data structure up to date so
* EEPROM size is known at compile time!
*/
typedef struct SettingsDataStruct {
char version[4]; // Vnn\0
uint16_t crc; // Data Checksum
//
// DISTINCT_E_FACTORS
//
uint8_t esteppers; // XYZE_N - XYZ
planner_settings_t planner_settings;
2019-09-29 11:25:39 +02:00
xyze_float_t planner_max_jerk; // M205 XYZE planner.max_jerk
float planner_junction_deviation_mm; // M205 J planner.junction_deviation_mm
2018-01-05 02:59:43 +01:00
2019-09-29 11:25:39 +02:00
xyz_pos_t home_offset; // M206 XYZ / M665 TPZ
2018-01-05 02:59:43 +01:00
2018-08-25 04:26:29 +02:00
#if HAS_HOTEND_OFFSET
2019-09-29 11:25:39 +02:00
xyz_pos_t hotend_offset[HOTENDS - 1]; // M218 XYZ
2018-01-05 02:59:43 +01:00
#endif
//
// FILAMENT_RUNOUT_SENSOR
//
bool runout_sensor_enabled; // M412 S
float runout_distance_mm; // M412 D
2018-01-05 02:59:43 +01:00
//
// ENABLE_LEVELING_FADE_HEIGHT
//
float planner_z_fade_height; // M420 Zn planner.z_fade_height
//
// MESH_BED_LEVELING
//
float mbl_z_offset; // mbl.z_offset
uint8_t mesh_num_x, mesh_num_y; // GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y
#if ENABLED(MESH_BED_LEVELING)
float mbl_z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y]; // mbl.z_values
#else
float mbl_z_values[3][3];
#endif
//
// HAS_BED_PROBE
//
2019-09-29 11:25:39 +02:00
xyz_pos_t probe_offset;
2018-01-05 02:59:43 +01:00
//
// ABL_PLANAR
//
matrix_3x3 planner_bed_level_matrix; // planner.bed_level_matrix
//
// AUTO_BED_LEVELING_BILINEAR
//
uint8_t grid_max_x, grid_max_y; // GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y
xy_pos_t bilinear_grid_spacing, bilinear_start; // G29 L F
2018-01-05 02:59:43 +01:00
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
2019-09-29 11:25:39 +02:00
bed_mesh_t z_values; // G29
2018-01-05 02:59:43 +01:00
#else
float z_values[3][3];
#endif
//
// AUTO_BED_LEVELING_UBL
//
bool planner_leveling_active; // M420 S planner.leveling_active
int8_t ubl_storage_slot; // ubl.storage_slot
2018-08-07 17:04:46 +02:00
//
// SERVO_ANGLES
//
uint16_t servo_angles[EEPROM_NUM_SERVOS][2]; // M281 P L U
2018-08-07 17:04:46 +02:00
2019-05-26 04:56:47 +02:00
//
// BLTOUCH
//
bool bltouch_last_written_mode;
2018-01-05 02:59:43 +01:00
//
// DELTA / [XYZ]_DUAL_ENDSTOPS
//
#if ENABLED(DELTA)
2019-09-29 11:25:39 +02:00
float delta_height; // M666 H
abc_float_t delta_endstop_adj; // M666 XYZ
float delta_radius, // M665 R
2018-01-05 02:59:43 +01:00
delta_diagonal_rod, // M665 L
delta_segments_per_second; // M665 S
2019-09-29 11:25:39 +02:00
abc_float_t delta_tower_angle_trim; // M665 XYZ
#elif EITHER(X_DUAL_ENDSTOPS, Y_DUAL_ENDSTOPS) || Z_MULTI_ENDSTOPS
float x2_endstop_adj, // M666 X
y2_endstop_adj, // M666 Y
z2_endstop_adj, // M666 Z (S2)
z3_endstop_adj; // M666 Z (S3)
2018-01-05 02:59:43 +01:00
#endif
//
// ULTIPANEL
//
int16_t ui_preheat_hotend_temp[2], // M145 S0 H
ui_preheat_bed_temp[2]; // M145 S0 B
uint8_t ui_preheat_fan_speed[2]; // M145 S0 F
2018-01-05 02:59:43 +01:00
//
// PIDTEMP
//
2019-11-26 10:34:43 +01:00
PIDCF_t hotendPID[HOTENDS]; // M301 En PIDCF / M303 En U
int16_t lpq_len; // M301 L
2018-01-05 02:59:43 +01:00
//
// PIDTEMPBED
//
PID_t bedPID; // M304 PID / M303 E-1 U
2018-01-05 02:59:43 +01:00
2019-05-07 01:51:06 +02:00
//
// User-defined Thermistors
//
#if HAS_USER_THERMISTORS
user_thermistor_t user_thermistor[USER_THERMISTORS]; // M305 P0 R4700 T100000 B3950
#endif
2018-01-05 02:59:43 +01:00
//
// HAS_LCD_CONTRAST
//
int16_t lcd_contrast; // M250 C
2018-01-05 02:59:43 +01:00
2018-11-17 03:47:07 +01:00
//
// POWER_LOSS_RECOVERY
//
bool recovery_enabled; // M413 S
2018-01-05 02:59:43 +01:00
//
// FWRETRACT
//
fwretract_settings_t fwretract_settings; // M207 S F Z W, M208 S F W R
2018-01-05 02:59:43 +01:00
bool autoretract_enabled; // M209 S
//
// !NO_VOLUMETRIC
//
bool parser_volumetric_enabled; // M200 D parser.volumetric_enabled
float planner_filament_size[EXTRUDERS]; // M200 T D planner.filament_size[]
2018-01-05 02:59:43 +01:00
//
// HAS_TRINAMIC
//
2018-10-03 09:48:49 +02:00
tmc_stepper_current_t tmc_stepper_current; // M906 X Y Z X2 Y2 Z2 Z3 E0 E1 E2 E3 E4 E5
tmc_hybrid_threshold_t tmc_hybrid_threshold; // M913 X Y Z X2 Y2 Z2 Z3 E0 E1 E2 E3 E4 E5
tmc_sgt_t tmc_sgt; // M914 X Y Z X2
tmc_stealth_enabled_t tmc_stealth_enabled; // M569 X Y Z X2 Y2 Z2 Z3 E0 E1 E2 E3 E4 E5
2018-01-05 02:59:43 +01:00
//
// LIN_ADVANCE
//
float planner_extruder_advance_K[EXTRUDERS]; // M900 K planner.extruder_advance_K
2018-01-05 02:59:43 +01:00
//
// HAS_MOTOR_CURRENT_PWM
//
uint32_t motor_current_setting[3]; // M907 X Z E
2018-01-05 02:59:43 +01:00
//
// CNC_COORDINATE_SYSTEMS
//
2019-09-29 11:25:39 +02:00
xyz_pos_t coordinate_system[MAX_COORDINATE_SYSTEMS]; // G54-G59.3
2018-01-05 02:59:43 +01:00
//
// SKEW_CORRECTION
//
skew_factor_t planner_skew_factor; // M852 I J K planner.skew_factor
2018-01-05 02:59:43 +01:00
//
// ADVANCED_PAUSE_FEATURE
//
2019-09-10 09:20:49 +02:00
#if EXTRUDERS
fil_change_settings_t fc_settings[EXTRUDERS]; // M603 T U L
#endif
2018-01-05 02:59:43 +01:00
2018-10-08 00:06:14 +02:00
//
// Tool-change settings
2018-10-08 00:06:14 +02:00
//
#if EXTRUDERS > 1
2018-11-17 03:47:07 +01:00
toolchange_settings_t toolchange_settings; // M217 S P R
2018-10-08 00:06:14 +02:00
#endif
//
// BACKLASH_COMPENSATION
//
2019-09-29 11:25:39 +02:00
xyz_float_t backlash_distance_mm; // M425 X Y Z
uint8_t backlash_correction; // M425 F
float backlash_smoothing_mm; // M425 S
//
// EXTENSIBLE_UI
//
#if ENABLED(EXTENSIBLE_UI)
// This is a significant hardware change; don't reserve space when not present
uint8_t extui_data[ExtUI::eeprom_data_size];
#endif
2018-01-05 02:59:43 +01:00
} SettingsData;
//static_assert(sizeof(SettingsData) <= E2END + 1, "EEPROM too small to contain SettingsData!");
2018-01-05 02:59:43 +01:00
MarlinSettings settings;
2018-01-05 03:01:25 +01:00
uint16_t MarlinSettings::datasize() { return sizeof(SettingsData); }
/**
* Post-process after Retrieve or Reset
*/
2018-01-05 02:59:43 +01:00
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
float new_z_fade_height;
#endif
2017-04-10 04:47:49 +02:00
void MarlinSettings::postprocess() {
2019-09-29 11:25:39 +02:00
xyze_pos_t oldpos = current_position;
// steps per s2 needs to be updated to agree with units per s2
planner.reset_acceleration_rates();
// Make sure delta kinematics are updated before refreshing the
// planner position so the stepper counts will be set correctly.
#if ENABLED(DELTA)
2017-11-08 10:07:17 +01:00
recalc_delta_settings();
#endif
#if ENABLED(PIDTEMP)
thermalManager.updatePID();
#endif
#if DISABLED(NO_VOLUMETRICS)
planner.calculate_volumetric_multipliers();
2019-09-10 09:20:49 +02:00
#elif EXTRUDERS
2017-12-27 03:04:39 +01:00
for (uint8_t i = COUNT(planner.e_factor); i--;)
planner.refresh_e_factor(i);
#endif
// Software endstops depend on home_offset
LOOP_XYZ(i) {
update_workspace_offset((AxisEnum)i);
update_software_endstops((AxisEnum)i);
}
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
set_z_fade_height(new_z_fade_height, false); // false = no report
#endif
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
refresh_bed_level();
#endif
#if HAS_MOTOR_CURRENT_PWM
stepper.refresh_motor_power();
#endif
2017-09-29 15:03:28 +02:00
#if ENABLED(FWRETRACT)
fwretract.refresh_autoretract();
#endif
2017-12-20 02:11:07 +01:00
#if HAS_LINEAR_E_JERK
planner.recalculate_max_e_jerk();
#endif
// Refresh steps_to_mm with the reciprocal of axis_steps_per_mm
// and init stepper.count[], planner.position[] with current_position
planner.refresh_positioning();
2017-11-04 22:36:41 +01:00
// Various factors can change the current position
2019-09-29 11:25:39 +02:00
if (oldpos != current_position)
report_current_position();
}
#if BOTH(PRINTCOUNTER, EEPROM_SETTINGS)
#include "printcounter.h"
static_assert(
!WITHIN(STATS_EEPROM_ADDRESS, EEPROM_OFFSET, EEPROM_OFFSET + sizeof(SettingsData)) &&
!WITHIN(STATS_EEPROM_ADDRESS + sizeof(printStatistics), EEPROM_OFFSET, EEPROM_OFFSET + sizeof(SettingsData)),
"STATS_EEPROM_ADDRESS collides with EEPROM settings storage."
);
#endif
#if ENABLED(SD_FIRMWARE_UPDATE)
#if ENABLED(EEPROM_SETTINGS)
static_assert(
!WITHIN(SD_FIRMWARE_UPDATE_EEPROM_ADDR, EEPROM_OFFSET, EEPROM_OFFSET + sizeof(SettingsData)),
"SD_FIRMWARE_UPDATE_EEPROM_ADDR collides with EEPROM settings storage."
);
#endif
bool MarlinSettings::sd_update_status() {
uint8_t val;
persistentStore.read_data(SD_FIRMWARE_UPDATE_EEPROM_ADDR, &val);
return (val == SD_FIRMWARE_UPDATE_ACTIVE_VALUE);
}
bool MarlinSettings::set_sd_update_status(const bool enable) {
if (enable != sd_update_status())
persistentStore.write_data(
SD_FIRMWARE_UPDATE_EEPROM_ADDR,
enable ? SD_FIRMWARE_UPDATE_ACTIVE_VALUE : SD_FIRMWARE_UPDATE_INACTIVE_VALUE
);
return true;
}
#endif // SD_FIRMWARE_UPDATE
#ifdef ARCHIM2_SPI_FLASH_EEPROM_BACKUP_SIZE
static_assert(
EEPROM_OFFSET + sizeof(SettingsData) < ARCHIM2_SPI_FLASH_EEPROM_BACKUP_SIZE,
"ARCHIM2_SPI_FLASH_EEPROM_BACKUP_SIZE is insufficient to capture all EEPROM data."
);
#endif
#define DEBUG_OUT ENABLED(EEPROM_CHITCHAT)
#include "../core/debug_out.h"
#if ENABLED(EEPROM_SETTINGS)
#define EEPROM_START() if (!persistentStore.access_start()) { SERIAL_ECHO_MSG("No EEPROM."); return false; } \
int eeprom_index = EEPROM_OFFSET
#define EEPROM_FINISH() persistentStore.access_finish()
#define EEPROM_SKIP(VAR) (eeprom_index += sizeof(VAR))
#define EEPROM_WRITE(VAR) do{ persistentStore.write_data(eeprom_index, (uint8_t*)&VAR, sizeof(VAR), &working_crc); }while(0)
#define EEPROM_READ(VAR) do{ persistentStore.read_data(eeprom_index, (uint8_t*)&VAR, sizeof(VAR), &working_crc, !validating); }while(0)
#define EEPROM_READ_ALWAYS(VAR) do{ persistentStore.read_data(eeprom_index, (uint8_t*)&VAR, sizeof(VAR), &working_crc); }while(0)
#define EEPROM_ASSERT(TST,ERR) do{ if (!(TST)) { SERIAL_ERROR_MSG(ERR); eeprom_error = true; } }while(0)
2018-01-05 03:27:17 +01:00
#if ENABLED(DEBUG_EEPROM_READWRITE)
2018-01-06 02:00:26 +01:00
#define _FIELD_TEST(FIELD) \
EEPROM_ASSERT( \
eeprom_error || eeprom_index == offsetof(SettingsData, FIELD) + EEPROM_OFFSET, \
2018-01-06 02:00:26 +01:00
"Field " STRINGIFY(FIELD) " mismatch." \
2018-01-05 03:27:17 +01:00
)
#else
#define _FIELD_TEST(FIELD) NOOP
#endif
2016-12-09 13:13:44 +01:00
const char version[4] = EEPROM_VERSION;
2018-01-05 02:51:18 +01:00
bool MarlinSettings::eeprom_error, MarlinSettings::validating;
2017-04-10 04:47:49 +02:00
2019-02-24 05:53:01 +01:00
bool MarlinSettings::size_error(const uint16_t size) {
2018-01-05 03:01:25 +01:00
if (size != datasize()) {
DEBUG_ERROR_MSG("EEPROM datasize error.");
2018-01-05 03:01:25 +01:00
return true;
}
return false;
}
2016-10-29 01:55:42 +02:00
/**
* M500 - Store Configuration
*/
2019-02-24 05:53:01 +01:00
bool MarlinSettings::save() {
2018-07-07 03:41:08 +02:00
float dummy = 0;
2018-01-06 02:00:26 +01:00
char ver[4] = "ERR";
uint16_t working_crc = 0;
2016-10-29 01:55:42 +02:00
EEPROM_START();
eeprom_error = false;
[2.0.x] Multiple updates to STM32F1 HAL (#8733) * STM32F1 HAL Adding files for STM32F1 HAL based on libmaple/stm32duino core. Current persistent_store uses cardreader changes to be sent in separate commit, but could be changed to use i2c eeprom. There is another persistent_store implementation that uses the MCU flash memory to emulate eeprom Adding readme with some information about the stm32 HAL. * Switch to Timer4 to avoid a hard reset on STM32F103C6 boards On bluepill STM32F103C6 boards, using Timer5 results in a error() vector call. Switch to 4 since these are both general purpose, 16 bit timers. * Add support for EEPROM emulation using Flash Some low end machines doe not have EEPROM support. Simulate it using the last two pages of flash. Flash does not allow rewrite between erases, so skip writing the working version if that's enabled. * Basic Pins for a malyan M200 This is a work in progress to go hand in hand with the STM32 work. * Add support for ADC with DMA. This work has exposed a problem with the pin enumerations in STM boards vs what marlin expects (i.e, try defining PA0 as a temp pin). The hack can be removed with we go to fastio completely. To see this work, set something in adc_pins to a value like PA0 and connect your pullup resistor'd thermistor. * Missing file - change HAL_adc_init to actually do something We have an actual ADC init function now. * Remove pinmode hack Remove the pin mode hack that I was using to init PA0. Updated Readme.md * Several changes to timers and GPIO Faster GPIO, and faster timer functions by accesing registers and libmaple. Still more changes pending for the Timer's code to skip using the HardwareTimer class altogether. Switch all enums to be within #defines This change allows a user to have, for instance, TEMP_4 and TEMP_BED definied but nothing else. The enums which are not defined move "out", allowing the first ones to take the slots in the enum, and since the array is sized on ADC_PIN_COUNT, we always have the right size data and in order. * Update Malyan M200 pins Update Malyan M200 pins with correct fan values. * Test all pins on actual hardware, update definitions Some of the pin definitions were from knowlege base/pdfs. Now they've been tested against actual hardware. This should be very close to final. * Update HAL_timers_Stm32f1.cpp * Add sample configurations for Malyan M200 Add sample configuration for Malyan M200 without bed leveling, and move fan to auto cool E0 since this printer by default has only one fan. Choose the timer based on MCU defintion. Timer5 is not valid on C8/CB class boards, so use Timer4 for the step timer. readme.md update * Updates to timers, and some stm32 boards definitiions * Correct pin toggle macro. * Remove duplicated Malyan M200 entry from pins.h * Update configuration_store.cpp * Formatting, indentation * Formatting in HAL_Stm32f1.cpp
2017-12-11 06:12:45 +01:00
#if ENABLED(FLASH_EEPROM_EMULATION)
EEPROM_SKIP(ver); // Flash doesn't allow rewriting without erase
#else
EEPROM_WRITE(ver); // invalidate data first
#endif
EEPROM_SKIP(working_crc); // Skip the checksum slot
2016-06-30 03:12:23 +02:00
working_crc = 0; // clear before first "real data"
2016-07-24 19:19:49 +02:00
2018-01-05 03:27:17 +01:00
_FIELD_TEST(esteppers);
const uint8_t esteppers = COUNT(planner.settings.axis_steps_per_mm) - XYZ;
EEPROM_WRITE(esteppers);
//
// Planner Motion
//
{
EEPROM_WRITE(planner.settings);
2018-01-05 03:27:17 +01:00
#if HAS_CLASSIC_JERK
EEPROM_WRITE(planner.max_jerk);
#if HAS_LINEAR_E_JERK
dummy = float(DEFAULT_EJERK);
EEPROM_WRITE(dummy);
#endif
#else
2019-09-29 11:25:39 +02:00
const xyze_pos_t planner_max_jerk = { 10, 10, 0.4, float(DEFAULT_EJERK) };
EEPROM_WRITE(planner_max_jerk);
#endif
#if DISABLED(CLASSIC_JERK)
EEPROM_WRITE(planner.junction_deviation_mm);
#else
dummy = 0.02f;
EEPROM_WRITE(dummy);
#endif
}
//
// Home Offset
//
{
_FIELD_TEST(home_offset);
2018-01-05 03:27:17 +01:00
#if HAS_SCARA_OFFSET
EEPROM_WRITE(scara_home_offset);
#else
#if !HAS_HOME_OFFSET
2019-09-29 11:25:39 +02:00
const xyz_pos_t home_offset{0};
#endif
EEPROM_WRITE(home_offset);
#endif
#if HAS_HOTEND_OFFSET
// Skip hotend 0 which must be 0
for (uint8_t e = 1; e < HOTENDS; e++)
2019-09-29 11:25:39 +02:00
EEPROM_WRITE(hotend_offset[e]);
#endif
}
//
// Filament Runout Sensor
//
{
#if HAS_FILAMENT_SENSOR
const bool &runout_sensor_enabled = runout.enabled;
#else
const bool runout_sensor_enabled = true;
#endif
#if HAS_FILAMENT_SENSOR && defined(FILAMENT_RUNOUT_DISTANCE_MM)
const float &runout_distance_mm = runout.runout_distance();
#else
const float runout_distance_mm = 0;
#endif
_FIELD_TEST(runout_sensor_enabled);
EEPROM_WRITE(runout_sensor_enabled);
EEPROM_WRITE(runout_distance_mm);
}
//
// Global Leveling
//
{
const float zfh = (
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
planner.z_fade_height
#else
10.0
#endif
);
EEPROM_WRITE(zfh);
}
//
// Mesh Bed Leveling
//
{
#if ENABLED(MESH_BED_LEVELING)
// Compile time test that sizeof(mbl.z_values) is as expected
static_assert(
sizeof(mbl.z_values) == (GRID_MAX_POINTS) * sizeof(mbl.z_values[0][0]),
"MBL Z array is the wrong size."
);
const uint8_t mesh_num_x = GRID_MAX_POINTS_X, mesh_num_y = GRID_MAX_POINTS_Y;
EEPROM_WRITE(mbl.z_offset);
EEPROM_WRITE(mesh_num_x);
EEPROM_WRITE(mesh_num_y);
EEPROM_WRITE(mbl.z_values);
#else // For disabled MBL write a default mesh
dummy = 0;
const uint8_t mesh_num_x = 3, mesh_num_y = 3;
EEPROM_WRITE(dummy); // z_offset
EEPROM_WRITE(mesh_num_x);
EEPROM_WRITE(mesh_num_y);
for (uint8_t q = mesh_num_x * mesh_num_y; q--;) EEPROM_WRITE(dummy);
2018-10-03 09:48:49 +02:00
#endif
}
2016-12-10 07:17:49 +01:00
//
2019-09-29 23:55:34 +02:00
// Probe XYZ Offsets
2016-12-10 07:17:49 +01:00
//
{
2019-09-29 23:55:34 +02:00
_FIELD_TEST(probe_offset);
2019-09-25 06:35:49 +02:00
EEPROM_WRITE(probe_offset);
}
2016-12-14 08:50:06 +01:00
//
// Planar Bed Leveling matrix
//
{
#if ABL_PLANAR
EEPROM_WRITE(planner.bed_level_matrix);
#else
dummy = 0;
for (uint8_t q = 9; q--;) EEPROM_WRITE(dummy);
#endif
}
2016-12-14 08:50:06 +01:00
2016-12-10 07:17:49 +01:00
//
// Bilinear Auto Bed Leveling
//
{
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
// Compile time test that sizeof(z_values) is as expected
static_assert(
sizeof(z_values) == (GRID_MAX_POINTS) * sizeof(z_values[0][0]),
"Bilinear Z array is the wrong size."
);
const uint8_t grid_max_x = GRID_MAX_POINTS_X, grid_max_y = GRID_MAX_POINTS_Y;
EEPROM_WRITE(grid_max_x); // 1 byte
EEPROM_WRITE(grid_max_y); // 1 byte
EEPROM_WRITE(bilinear_grid_spacing); // 2 ints
EEPROM_WRITE(bilinear_start); // 2 ints
EEPROM_WRITE(z_values); // 9-256 floats
#else
// For disabled Bilinear Grid write an empty 3x3 grid
const uint8_t grid_max_x = 3, grid_max_y = 3;
const xy_pos_t bilinear_start{0}, bilinear_grid_spacing{0};
dummy = 0;
EEPROM_WRITE(grid_max_x);
EEPROM_WRITE(grid_max_y);
EEPROM_WRITE(bilinear_grid_spacing);
EEPROM_WRITE(bilinear_start);
for (uint16_t q = grid_max_x * grid_max_y; q--;) EEPROM_WRITE(dummy);
2018-08-25 04:53:42 +02:00
#endif
}
//
// Unified Bed Leveling
//
{
_FIELD_TEST(planner_leveling_active);
#if ENABLED(AUTO_BED_LEVELING_UBL)
EEPROM_WRITE(planner.leveling_active);
EEPROM_WRITE(ubl.storage_slot);
#else
const bool ubl_active = false;
const int8_t storage_slot = -1;
EEPROM_WRITE(ubl_active);
EEPROM_WRITE(storage_slot);
#endif // AUTO_BED_LEVELING_UBL
}
//
// Servo Angles
//
{
_FIELD_TEST(servo_angles);
2018-08-25 04:53:42 +02:00
#if !HAS_SERVO_ANGLES
uint16_t servo_angles[EEPROM_NUM_SERVOS][2] = { { 0, 0 } };
#endif
EEPROM_WRITE(servo_angles);
}
2018-01-10 01:33:44 +01:00
2019-05-26 04:56:47 +02:00
//
// BLTOUCH
//
{
_FIELD_TEST(bltouch_last_written_mode);
#if ENABLED(BLTOUCH)
const bool &bltouch_last_written_mode = bltouch.last_written_mode;
#else
constexpr bool bltouch_last_written_mode = false;
#endif
EEPROM_WRITE(bltouch_last_written_mode);
}
//
// DELTA Geometry or Dual Endstops offsets
//
{
#if ENABLED(DELTA)
2018-01-10 01:33:44 +01:00
_FIELD_TEST(delta_height);
EEPROM_WRITE(delta_height); // 1 float
EEPROM_WRITE(delta_endstop_adj); // 3 floats
EEPROM_WRITE(delta_radius); // 1 float
EEPROM_WRITE(delta_diagonal_rod); // 1 float
EEPROM_WRITE(delta_segments_per_second); // 1 float
EEPROM_WRITE(delta_tower_angle_trim); // 3 floats
2018-01-10 01:33:44 +01:00
#elif EITHER(X_DUAL_ENDSTOPS, Y_DUAL_ENDSTOPS) || Z_MULTI_ENDSTOPS
2018-01-10 01:33:44 +01:00
_FIELD_TEST(x2_endstop_adj);
// Write dual endstops in X, Y, Z order. Unused = 0.0
dummy = 0;
#if ENABLED(X_DUAL_ENDSTOPS)
EEPROM_WRITE(endstops.x2_endstop_adj); // 1 float
#else
EEPROM_WRITE(dummy);
#endif
#if ENABLED(Y_DUAL_ENDSTOPS)
EEPROM_WRITE(endstops.y2_endstop_adj); // 1 float
#else
EEPROM_WRITE(dummy);
#endif
#if Z_MULTI_ENDSTOPS
EEPROM_WRITE(endstops.z2_endstop_adj); // 1 float
#else
EEPROM_WRITE(dummy);
#endif
#if ENABLED(Z_TRIPLE_ENDSTOPS)
EEPROM_WRITE(endstops.z3_endstop_adj); // 1 float
#else
EEPROM_WRITE(dummy);
#endif
#endif
}
2018-01-05 03:27:17 +01:00
//
// LCD Preheat settings
//
{
_FIELD_TEST(ui_preheat_hotend_temp);
2016-10-29 01:55:42 +02:00
2019-09-10 09:20:49 +02:00
#if HOTENDS && HAS_LCD_MENU
const int16_t (&ui_preheat_hotend_temp)[2] = ui.preheat_hotend_temp,
(&ui_preheat_bed_temp)[2] = ui.preheat_bed_temp;
const uint8_t (&ui_preheat_fan_speed)[2] = ui.preheat_fan_speed;
#else
constexpr int16_t ui_preheat_hotend_temp[2] = { PREHEAT_1_TEMP_HOTEND, PREHEAT_2_TEMP_HOTEND },
ui_preheat_bed_temp[2] = { PREHEAT_1_TEMP_BED, PREHEAT_2_TEMP_BED };
constexpr uint8_t ui_preheat_fan_speed[2] = { PREHEAT_1_FAN_SPEED, PREHEAT_2_FAN_SPEED };
#endif
EEPROM_WRITE(ui_preheat_hotend_temp);
EEPROM_WRITE(ui_preheat_bed_temp);
EEPROM_WRITE(ui_preheat_fan_speed);
}
2016-10-29 01:55:42 +02:00
//
// PIDTEMP
//
{
_FIELD_TEST(hotendPID);
HOTEND_LOOP() {
2019-11-26 10:34:43 +01:00
PIDCF_t pidcf = {
PID_PARAM(Kp, e),
unscalePID_i(PID_PARAM(Ki, e)),
unscalePID_d(PID_PARAM(Kd, e)),
2019-11-26 10:34:43 +01:00
PID_PARAM(Kc, e),
PID_PARAM(Kf, e)
};
2019-11-26 10:34:43 +01:00
EEPROM_WRITE(pidcf);
}
_FIELD_TEST(lpq_len);
#if ENABLED(PID_EXTRUSION_SCALING)
EEPROM_WRITE(thermalManager.lpq_len);
#else
const int16_t lpq_len = 20;
EEPROM_WRITE(lpq_len);
#endif
}
2018-01-10 01:33:44 +01:00
//
// PIDTEMPBED
//
{
_FIELD_TEST(bedPID);
const PID_t bed_pid = {
#if DISABLED(PIDTEMPBED)
DUMMY_PID_VALUE, DUMMY_PID_VALUE, DUMMY_PID_VALUE
#else
// Store the unscaled PID values
thermalManager.temp_bed.pid.Kp,
unscalePID_i(thermalManager.temp_bed.pid.Ki),
unscalePID_d(thermalManager.temp_bed.pid.Kd)
#endif
};
EEPROM_WRITE(bed_pid);
}
2016-10-29 01:55:42 +02:00
2019-05-07 01:51:06 +02:00
//
// User-defined Thermistors
//
#if HAS_USER_THERMISTORS
{
_FIELD_TEST(user_thermistor);
EEPROM_WRITE(thermalManager.user_thermistor);
}
#endif
//
// LCD Contrast
//
{
_FIELD_TEST(lcd_contrast);
2015-04-04 01:38:05 +02:00
const int16_t lcd_contrast =
#if HAS_LCD_CONTRAST
ui.contrast
#elif defined(DEFAULT_LCD_CONTRAST)
DEFAULT_LCD_CONTRAST
#else
127
#endif
;
EEPROM_WRITE(lcd_contrast);
}
2018-11-17 03:47:07 +01:00
//
// Power-Loss Recovery
//
{
_FIELD_TEST(recovery_enabled);
const bool recovery_enabled =
#if ENABLED(POWER_LOSS_RECOVERY)
recovery.enabled
#else
true
#endif
;
EEPROM_WRITE(recovery_enabled);
}
//
// Firmware Retraction
//
{
_FIELD_TEST(fwretract_settings);
#if ENABLED(FWRETRACT)
EEPROM_WRITE(fwretract.settings);
#else
const fwretract_settings_t autoretract_defaults = { 3, 45, 0, 0, 0, 13, 0, 8 };
EEPROM_WRITE(autoretract_defaults);
#endif
#if BOTH(FWRETRACT, FWRETRACT_AUTORETRACT)
EEPROM_WRITE(fwretract.autoretract_enabled);
#else
const bool autoretract_enabled = false;
EEPROM_WRITE(autoretract_enabled);
#endif
}
//
// Volumetric & Filament Size
//
{
_FIELD_TEST(parser_volumetric_enabled);
2018-01-10 01:33:44 +01:00
#if DISABLED(NO_VOLUMETRICS)
EEPROM_WRITE(parser.volumetric_enabled);
EEPROM_WRITE(planner.filament_size);
#else
2018-01-05 03:23:24 +01:00
const bool volumetric_enabled = false;
dummy = DEFAULT_NOMINAL_FILAMENT_DIA;
EEPROM_WRITE(volumetric_enabled);
for (uint8_t q = EXTRUDERS; q--;) EEPROM_WRITE(dummy);
2018-01-05 03:23:24 +01:00
#endif
}
2018-01-05 02:47:42 +01:00
//
// TMC Configuration
2018-01-05 02:47:42 +01:00
//
{
_FIELD_TEST(tmc_stepper_current);
2018-01-10 01:33:44 +01:00
tmc_stepper_current_t tmc_stepper_current = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
2018-10-03 09:48:49 +02:00
#if HAS_TRINAMIC
#if AXIS_IS_TMC(X)
tmc_stepper_current.X = stepperX.getMilliamps();
#endif
#if AXIS_IS_TMC(Y)
tmc_stepper_current.Y = stepperY.getMilliamps();
#endif
#if AXIS_IS_TMC(Z)
tmc_stepper_current.Z = stepperZ.getMilliamps();
#endif
#if AXIS_IS_TMC(X2)
tmc_stepper_current.X2 = stepperX2.getMilliamps();
#endif
#if AXIS_IS_TMC(Y2)
tmc_stepper_current.Y2 = stepperY2.getMilliamps();
#endif
#if AXIS_IS_TMC(Z2)
tmc_stepper_current.Z2 = stepperZ2.getMilliamps();
#endif
#if AXIS_IS_TMC(Z3)
tmc_stepper_current.Z3 = stepperZ3.getMilliamps();
#endif
#if MAX_EXTRUDERS
#if AXIS_IS_TMC(E0)
tmc_stepper_current.E0 = stepperE0.getMilliamps();
#endif
#if MAX_EXTRUDERS > 1
#if AXIS_IS_TMC(E1)
tmc_stepper_current.E1 = stepperE1.getMilliamps();
#endif
#if MAX_EXTRUDERS > 2
#if AXIS_IS_TMC(E2)
tmc_stepper_current.E2 = stepperE2.getMilliamps();
#endif
#if MAX_EXTRUDERS > 3
#if AXIS_IS_TMC(E3)
tmc_stepper_current.E3 = stepperE3.getMilliamps();
#endif
#if MAX_EXTRUDERS > 4
#if AXIS_IS_TMC(E4)
tmc_stepper_current.E4 = stepperE4.getMilliamps();
#endif
#if MAX_EXTRUDERS > 5
#if AXIS_IS_TMC(E5)
tmc_stepper_current.E5 = stepperE5.getMilliamps();
#endif
#endif // MAX_EXTRUDERS > 5
#endif // MAX_EXTRUDERS > 4
#endif // MAX_EXTRUDERS > 3
#endif // MAX_EXTRUDERS > 2
#endif // MAX_EXTRUDERS > 1
#endif // MAX_EXTRUDERS
#endif
EEPROM_WRITE(tmc_stepper_current);
}
2018-03-15 04:03:53 +01:00
//
// TMC Hybrid Threshold, and placeholder values
2018-03-15 04:03:53 +01:00
//
{
_FIELD_TEST(tmc_hybrid_threshold);
2018-03-15 04:03:53 +01:00
#if ENABLED(HYBRID_THRESHOLD)
tmc_hybrid_threshold_t tmc_hybrid_threshold = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
#if AXIS_HAS_STEALTHCHOP(X)
tmc_hybrid_threshold.X = stepperX.get_pwm_thrs();
#endif
#if AXIS_HAS_STEALTHCHOP(Y)
tmc_hybrid_threshold.Y = stepperY.get_pwm_thrs();
#endif
#if AXIS_HAS_STEALTHCHOP(Z)
tmc_hybrid_threshold.Z = stepperZ.get_pwm_thrs();
#endif
#if AXIS_HAS_STEALTHCHOP(X2)
tmc_hybrid_threshold.X2 = stepperX2.get_pwm_thrs();
#endif
#if AXIS_HAS_STEALTHCHOP(Y2)
tmc_hybrid_threshold.Y2 = stepperY2.get_pwm_thrs();
#endif
#if AXIS_HAS_STEALTHCHOP(Z2)
tmc_hybrid_threshold.Z2 = stepperZ2.get_pwm_thrs();
#endif
#if AXIS_HAS_STEALTHCHOP(Z3)
tmc_hybrid_threshold.Z3 = stepperZ3.get_pwm_thrs();
#endif
#if MAX_EXTRUDERS
#if AXIS_HAS_STEALTHCHOP(E0)
tmc_hybrid_threshold.E0 = stepperE0.get_pwm_thrs();
#endif
#if MAX_EXTRUDERS > 1
#if AXIS_HAS_STEALTHCHOP(E1)
tmc_hybrid_threshold.E1 = stepperE1.get_pwm_thrs();
#endif
#if MAX_EXTRUDERS > 2
#if AXIS_HAS_STEALTHCHOP(E2)
tmc_hybrid_threshold.E2 = stepperE2.get_pwm_thrs();
#endif
#if MAX_EXTRUDERS > 3
#if AXIS_HAS_STEALTHCHOP(E3)
tmc_hybrid_threshold.E3 = stepperE3.get_pwm_thrs();
#endif
#if MAX_EXTRUDERS > 4
#if AXIS_HAS_STEALTHCHOP(E4)
tmc_hybrid_threshold.E4 = stepperE4.get_pwm_thrs();
#endif
#if MAX_EXTRUDERS > 5
#if AXIS_HAS_STEALTHCHOP(E5)
tmc_hybrid_threshold.E5 = stepperE5.get_pwm_thrs();
#endif
#endif // MAX_EXTRUDERS > 5
#endif // MAX_EXTRUDERS > 4
#endif // MAX_EXTRUDERS > 3
#endif // MAX_EXTRUDERS > 2
#endif // MAX_EXTRUDERS > 1
#endif // MAX_EXTRUDERS
#else
const tmc_hybrid_threshold_t tmc_hybrid_threshold = {
.X = 100, .Y = 100, .Z = 3,
.X2 = 100, .Y2 = 100, .Z2 = 3, .Z3 = 3,
.E0 = 30, .E1 = 30, .E2 = 30,
.E3 = 30, .E4 = 30, .E5 = 30
};
#endif
EEPROM_WRITE(tmc_hybrid_threshold);
}
2017-12-15 22:03:14 +01:00
//
2018-10-03 09:48:49 +02:00
// TMC StallGuard threshold
2017-12-15 22:03:14 +01:00
//
{
2019-09-29 11:25:39 +02:00
tmc_sgt_t tmc_sgt{0};
#if USE_SENSORLESS
#if X_SENSORLESS
2019-06-20 22:47:50 +02:00
tmc_sgt.X = stepperX.homing_threshold();
#endif
#if X2_SENSORLESS
tmc_sgt.X2 = stepperX2.homing_threshold();
#endif
#if Y_SENSORLESS
2019-06-20 22:47:50 +02:00
tmc_sgt.Y = stepperY.homing_threshold();
#endif
#if Z_SENSORLESS
2019-06-20 22:47:50 +02:00
tmc_sgt.Z = stepperZ.homing_threshold();
#endif
2018-10-03 09:48:49 +02:00
#endif
EEPROM_WRITE(tmc_sgt);
}
2017-12-15 22:03:14 +01:00
//
// TMC stepping mode
//
{
_FIELD_TEST(tmc_stealth_enabled);
tmc_stealth_enabled_t tmc_stealth_enabled = { false, false, false, false, false, false, false, false, false, false, false, false, false };
#if HAS_STEALTHCHOP
#if AXIS_HAS_STEALTHCHOP(X)
tmc_stealth_enabled.X = stepperX.get_stealthChop_status();
#endif
#if AXIS_HAS_STEALTHCHOP(Y)
tmc_stealth_enabled.Y = stepperY.get_stealthChop_status();
#endif
#if AXIS_HAS_STEALTHCHOP(Z)
tmc_stealth_enabled.Z = stepperZ.get_stealthChop_status();
#endif
#if AXIS_HAS_STEALTHCHOP(X2)
tmc_stealth_enabled.X2 = stepperX2.get_stealthChop_status();
#endif
#if AXIS_HAS_STEALTHCHOP(Y2)
tmc_stealth_enabled.Y2 = stepperY2.get_stealthChop_status();
#endif
#if AXIS_HAS_STEALTHCHOP(Z2)
tmc_stealth_enabled.Z2 = stepperZ2.get_stealthChop_status();
#endif
#if AXIS_HAS_STEALTHCHOP(Z3)
tmc_stealth_enabled.Z3 = stepperZ3.get_stealthChop_status();
#endif
#if MAX_EXTRUDERS
#if AXIS_HAS_STEALTHCHOP(E0)
tmc_stealth_enabled.E0 = stepperE0.get_stealthChop_status();
#endif
#if MAX_EXTRUDERS > 1
#if AXIS_HAS_STEALTHCHOP(E1)
tmc_stealth_enabled.E1 = stepperE1.get_stealthChop_status();
#endif
#if MAX_EXTRUDERS > 2
#if AXIS_HAS_STEALTHCHOP(E2)
tmc_stealth_enabled.E2 = stepperE2.get_stealthChop_status();
#endif
#if MAX_EXTRUDERS > 3
#if AXIS_HAS_STEALTHCHOP(E3)
tmc_stealth_enabled.E3 = stepperE3.get_stealthChop_status();
#endif
#if MAX_EXTRUDERS > 4
#if AXIS_HAS_STEALTHCHOP(E4)
tmc_stealth_enabled.E4 = stepperE4.get_stealthChop_status();
#endif
#if MAX_EXTRUDERS > 5
#if AXIS_HAS_STEALTHCHOP(E5)
tmc_stealth_enabled.E5 = stepperE5.get_stealthChop_status();
#endif
#endif // MAX_EXTRUDERS > 5
#endif // MAX_EXTRUDERS > 4
#endif // MAX_EXTRUDERS > 3
#endif // MAX_EXTRUDERS > 2
#endif // MAX_EXTRUDERS > 1
#endif // MAX_EXTRUDERS
#endif
EEPROM_WRITE(tmc_stealth_enabled);
}
//
// Linear Advance
//
{
_FIELD_TEST(planner_extruder_advance_K);
2018-10-03 18:32:09 +02:00
#if ENABLED(LIN_ADVANCE)
EEPROM_WRITE(planner.extruder_advance_K);
#else
dummy = 0;
for (uint8_t q = EXTRUDERS; q--;) EEPROM_WRITE(dummy);
#endif
}
2018-01-10 01:33:44 +01:00
2018-10-03 18:32:09 +02:00
//
// Motor Current PWM
//
{
_FIELD_TEST(motor_current_setting);
2018-10-03 18:32:09 +02:00
#if HAS_MOTOR_CURRENT_PWM
EEPROM_WRITE(stepper.motor_current_setting);
#else
2019-09-29 11:25:39 +02:00
const xyz_ulong_t no_current{0};
EEPROM_WRITE(no_current);
#endif
}
2017-12-01 23:42:23 +01:00
//
// CNC Coordinate Systems
//
2018-01-10 01:33:44 +01:00
2018-01-05 03:27:17 +01:00
_FIELD_TEST(coordinate_system);
2018-01-10 01:33:44 +01:00
2017-11-04 22:36:41 +01:00
#if ENABLED(CNC_COORDINATE_SYSTEMS)
EEPROM_WRITE(gcode.coordinate_system);
2017-11-04 22:36:41 +01:00
#else
2019-09-29 11:25:39 +02:00
const xyz_pos_t coordinate_system[MAX_COORDINATE_SYSTEMS] = { { 0 } };
EEPROM_WRITE(coordinate_system);
2017-11-04 22:36:41 +01:00
#endif
2017-12-01 23:42:23 +01:00
//
// Skew correction factors
//
_FIELD_TEST(planner_skew_factor);
EEPROM_WRITE(planner.skew_factor);
2017-12-01 23:42:23 +01:00
//
// Advanced Pause filament load & unload lengths
//
2019-09-10 09:20:49 +02:00
#if EXTRUDERS
{
#if DISABLED(ADVANCED_PAUSE_FEATURE)
2018-10-26 10:53:06 +02:00
const fil_change_settings_t fc_settings[EXTRUDERS] = { 0, 0 };
#endif
_FIELD_TEST(fc_settings);
EEPROM_WRITE(fc_settings);
}
2019-09-10 09:20:49 +02:00
#endif
2018-10-08 00:06:14 +02:00
//
// Multiple Extruders
2018-10-08 00:06:14 +02:00
//
#if EXTRUDERS > 1
_FIELD_TEST(toolchange_settings);
EEPROM_WRITE(toolchange_settings);
2018-10-08 00:06:14 +02:00
#endif
//
// Backlash Compensation
//
{
#if ENABLED(BACKLASH_GCODE)
2019-09-29 11:25:39 +02:00
const xyz_float_t &backlash_distance_mm = backlash.distance_mm;
2019-05-21 04:34:08 +02:00
const uint8_t &backlash_correction = backlash.correction;
#else
2019-09-29 11:25:39 +02:00
const xyz_float_t backlash_distance_mm{0};
2019-05-21 04:34:08 +02:00
const uint8_t backlash_correction = 0;
#endif
#if ENABLED(BACKLASH_GCODE) && defined(BACKLASH_SMOOTHING_MM)
2019-05-21 04:34:08 +02:00
const float &backlash_smoothing_mm = backlash.smoothing_mm;
#else
2019-05-21 04:34:08 +02:00
const float backlash_smoothing_mm = 3;
#endif
_FIELD_TEST(backlash_distance_mm);
EEPROM_WRITE(backlash_distance_mm);
EEPROM_WRITE(backlash_correction);
EEPROM_WRITE(backlash_smoothing_mm);
}
//
// Extensible UI User Data
//
#if ENABLED(EXTENSIBLE_UI)
{
char extui_data[ExtUI::eeprom_data_size] = { 0 };
ExtUI::onStoreSettings(extui_data);
_FIELD_TEST(extui_data);
EEPROM_WRITE(extui_data);
}
#endif
2018-01-05 02:51:18 +01:00
//
2018-01-05 03:01:25 +01:00
// Validate CRC and Data Size
2018-01-05 02:51:18 +01:00
//
if (!eeprom_error) {
2018-01-05 02:59:43 +01:00
const uint16_t eeprom_size = eeprom_index - (EEPROM_OFFSET),
final_crc = working_crc;
2017-05-11 16:48:16 +02:00
// Write the EEPROM header
eeprom_index = EEPROM_OFFSET;
2017-05-11 16:48:16 +02:00
EEPROM_WRITE(version);
EEPROM_WRITE(final_crc);
2016-10-29 01:55:42 +02:00
// Report storage size
DEBUG_ECHO_START();
DEBUG_ECHOLNPAIR("Settings Stored (", eeprom_size, " bytes; crc ", (uint32_t)final_crc, ")");
2018-01-05 03:01:25 +01:00
eeprom_error |= size_error(eeprom_size);
}
EEPROM_FINISH();
2018-01-05 02:51:18 +01:00
//
// UBL Mesh
//
#if ENABLED(UBL_SAVE_ACTIVE_ON_M500)
2017-10-14 04:56:27 +02:00
if (ubl.storage_slot >= 0)
store_mesh(ubl.storage_slot);
2017-03-18 16:15:54 +01:00
#endif
#if ENABLED(EXTENSIBLE_UI)
ExtUI::onConfigurationStoreWritten(!eeprom_error);
#endif
return !eeprom_error;
2016-10-29 01:55:42 +02:00
}
/**
* M501 - Retrieve Configuration
*/
2019-02-24 05:53:01 +01:00
bool MarlinSettings::_load() {
uint16_t working_crc = 0;
2016-10-29 01:55:42 +02:00
EEPROM_START();
char stored_ver[4];
2018-01-05 02:51:18 +01:00
EEPROM_READ_ALWAYS(stored_ver);
2016-10-29 01:55:42 +02:00
uint16_t stored_crc;
2018-01-05 02:51:18 +01:00
EEPROM_READ_ALWAYS(stored_crc);
2016-10-29 01:55:42 +02:00
// Version has to match or defaults are used
2016-10-29 01:55:42 +02:00
if (strncmp(version, stored_ver, 3) != 0) {
2018-01-06 02:00:26 +01:00
if (stored_ver[3] != '\0') {
stored_ver[0] = '?';
stored_ver[1] = '\0';
}
DEBUG_ECHO_START();
DEBUG_ECHOLNPAIR("EEPROM version mismatch (EEPROM=", stored_ver, " Marlin=" EEPROM_VERSION ")");
2018-01-05 02:51:18 +01:00
eeprom_error = true;
2016-06-30 03:12:23 +02:00
}
2016-10-29 01:55:42 +02:00
else {
2018-07-07 03:41:08 +02:00
float dummy = 0;
working_crc = 0; // Init to 0. Accumulated by EEPROM_READ
2016-10-29 01:55:42 +02:00
2018-01-10 01:33:44 +01:00
_FIELD_TEST(esteppers);
// Number of esteppers may change
uint8_t esteppers;
2018-01-05 02:51:18 +01:00
EEPROM_READ_ALWAYS(esteppers);
2017-11-04 21:34:24 +01:00
//
// Planner Motion
//
2018-10-31 22:39:49 +01:00
{
// Get only the number of E stepper parameters previously stored
// Any steppers added later are set to their defaults
uint32_t tmp1[XYZ + esteppers];
2019-09-26 08:28:09 +02:00
float tmp2[XYZ + esteppers];
feedRate_t tmp3[XYZ + esteppers];
2018-10-31 22:39:49 +01:00
EEPROM_READ(tmp1); // max_acceleration_mm_per_s2
EEPROM_READ(planner.settings.min_segment_time_us);
EEPROM_READ(tmp2); // axis_steps_per_mm
EEPROM_READ(tmp3); // max_feedrate_mm_s
2019-09-26 08:28:09 +02:00
2018-10-31 22:39:49 +01:00
if (!validating) LOOP_XYZE_N(i) {
const bool in = (i < esteppers + XYZ);
2019-09-26 08:28:09 +02:00
planner.settings.max_acceleration_mm_per_s2[i] = in ? tmp1[i] : pgm_read_dword(&_DMA[ALIM(i, _DMA)]);
planner.settings.axis_steps_per_mm[i] = in ? tmp2[i] : pgm_read_float(&_DASU[ALIM(i, _DASU)]);
planner.settings.max_feedrate_mm_s[i] = in ? tmp3[i] : pgm_read_float(&_DMF[ALIM(i, _DMF)]);
2018-10-31 22:39:49 +01:00
}
2017-11-04 21:34:24 +01:00
2018-10-31 22:39:49 +01:00
EEPROM_READ(planner.settings.acceleration);
EEPROM_READ(planner.settings.retract_acceleration);
EEPROM_READ(planner.settings.travel_acceleration);
EEPROM_READ(planner.settings.min_feedrate_mm_s);
EEPROM_READ(planner.settings.min_travel_feedrate_mm_s);
2016-10-29 01:55:42 +02:00
2018-10-31 22:39:49 +01:00
#if HAS_CLASSIC_JERK
EEPROM_READ(planner.max_jerk);
#if HAS_LINEAR_E_JERK
2018-10-31 22:39:49 +01:00
EEPROM_READ(dummy);
#endif
#else
for (uint8_t q = 4; q--;) EEPROM_READ(dummy);
#endif
2017-03-05 01:01:33 +01:00
#if DISABLED(CLASSIC_JERK)
2018-10-31 22:39:49 +01:00
EEPROM_READ(planner.junction_deviation_mm);
#else
EEPROM_READ(dummy);
#endif
2018-10-31 22:39:49 +01:00
}
2017-11-04 21:34:24 +01:00
//
// Home Offset (M206 / M665)
2017-11-04 21:34:24 +01:00
//
2018-10-31 22:39:49 +01:00
{
_FIELD_TEST(home_offset);
2017-11-04 21:34:24 +01:00
#if HAS_SCARA_OFFSET
EEPROM_READ(scara_home_offset);
#else
#if !HAS_HOME_OFFSET
2019-09-29 11:25:39 +02:00
xyz_pos_t home_offset;
#endif
EEPROM_READ(home_offset);
2018-10-31 22:39:49 +01:00
#endif
}
2016-10-29 01:55:42 +02:00
2017-11-04 21:34:24 +01:00
//
// Hotend Offsets, if any
//
2018-10-31 22:39:49 +01:00
{
#if HAS_HOTEND_OFFSET
// Skip hotend 0 which must be 0
for (uint8_t e = 1; e < HOTENDS; e++)
2019-09-29 11:25:39 +02:00
EEPROM_READ(hotend_offset[e]);
2018-10-31 22:39:49 +01:00
#endif
}
2016-10-29 01:55:42 +02:00
//
// Filament Runout Sensor
//
{
#if HAS_FILAMENT_SENSOR
bool &runout_sensor_enabled = runout.enabled;
#else
bool runout_sensor_enabled;
#endif
_FIELD_TEST(runout_sensor_enabled);
EEPROM_READ(runout_sensor_enabled);
float runout_distance_mm;
EEPROM_READ(runout_distance_mm);
#if HAS_FILAMENT_SENSOR && defined(FILAMENT_RUNOUT_DISTANCE_MM)
if (!validating) runout.set_runout_distance(runout_distance_mm);
#endif
}
//
// Global Leveling
//
2018-10-31 22:39:49 +01:00
{
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
EEPROM_READ(new_z_fade_height);
#else
EEPROM_READ(dummy);
#endif
}
2016-12-10 07:17:49 +01:00
//
// Mesh (Manual) Bed Leveling
//
2018-10-31 22:39:49 +01:00
{
uint8_t mesh_num_x, mesh_num_y;
EEPROM_READ(dummy);
EEPROM_READ_ALWAYS(mesh_num_x);
EEPROM_READ_ALWAYS(mesh_num_y);
#if ENABLED(MESH_BED_LEVELING)
if (!validating) mbl.z_offset = dummy;
if (mesh_num_x == GRID_MAX_POINTS_X && mesh_num_y == GRID_MAX_POINTS_Y) {
// EEPROM data fits the current mesh
EEPROM_READ(mbl.z_values);
}
else {
// EEPROM data is stale
if (!validating) mbl.reset();
for (uint16_t q = mesh_num_x * mesh_num_y; q--;) EEPROM_READ(dummy);
}
#else
// MBL is disabled - skip the stored data
2016-12-10 07:17:49 +01:00
for (uint16_t q = mesh_num_x * mesh_num_y; q--;) EEPROM_READ(dummy);
2018-10-31 22:39:49 +01:00
#endif // MESH_BED_LEVELING
}
2016-10-29 01:55:42 +02:00
2018-10-31 22:39:49 +01:00
//
// Probe Z Offset
//
{
2019-09-29 11:25:39 +02:00
_FIELD_TEST(probe_offset);
2019-09-25 04:29:21 +02:00
#if HAS_BED_PROBE
2019-09-29 11:25:39 +02:00
xyz_pos_t &zpo = probe_offset;
2019-09-25 04:29:21 +02:00
#else
2019-09-29 11:25:39 +02:00
xyz_pos_t zpo;
2018-10-31 22:39:49 +01:00
#endif
2019-09-25 04:29:21 +02:00
EEPROM_READ(zpo);
2018-10-31 22:39:49 +01:00
}
2016-10-29 01:55:42 +02:00
2016-12-14 08:50:06 +01:00
//
// Planar Bed Leveling matrix
//
2018-10-31 22:39:49 +01:00
{
#if ABL_PLANAR
EEPROM_READ(planner.bed_level_matrix);
#else
for (uint8_t q = 9; q--;) EEPROM_READ(dummy);
#endif
}
2016-12-14 08:50:06 +01:00
2016-12-10 07:17:49 +01:00
//
// Bilinear Auto Bed Leveling
//
2018-10-31 22:39:49 +01:00
{
uint8_t grid_max_x, grid_max_y;
EEPROM_READ_ALWAYS(grid_max_x); // 1 byte
EEPROM_READ_ALWAYS(grid_max_y); // 1 byte
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
if (grid_max_x == GRID_MAX_POINTS_X && grid_max_y == GRID_MAX_POINTS_Y) {
if (!validating) set_bed_leveling_enabled(false);
EEPROM_READ(bilinear_grid_spacing); // 2 ints
EEPROM_READ(bilinear_start); // 2 ints
EEPROM_READ(z_values); // 9 to 256 floats
}
else // EEPROM data is stale
#endif // AUTO_BED_LEVELING_BILINEAR
{
// Skip past disabled (or stale) Bilinear Grid data
xy_pos_t bgs, bs;
2018-10-31 22:39:49 +01:00
EEPROM_READ(bgs);
EEPROM_READ(bs);
for (uint16_t q = grid_max_x * grid_max_y; q--;) EEPROM_READ(dummy);
}
}
2016-12-10 07:17:49 +01:00
2017-11-04 21:34:24 +01:00
//
// Unified Bed Leveling active state
//
2018-10-31 22:39:49 +01:00
{
_FIELD_TEST(planner_leveling_active);
2017-11-04 21:34:24 +01:00
2018-10-31 22:39:49 +01:00
#if ENABLED(AUTO_BED_LEVELING_UBL)
EEPROM_READ(planner.leveling_active);
EEPROM_READ(ubl.storage_slot);
#else
bool planner_leveling_active;
uint8_t ubl_storage_slot;
EEPROM_READ(planner_leveling_active);
EEPROM_READ(ubl_storage_slot);
#endif
}
2018-08-07 17:04:46 +02:00
//
// SERVO_ANGLES
//
2018-10-31 22:39:49 +01:00
{
_FIELD_TEST(servo_angles);
#if ENABLED(EDITABLE_SERVO_ANGLES)
uint16_t (&servo_angles_arr)[EEPROM_NUM_SERVOS][2] = servo_angles;
#else
uint16_t servo_angles_arr[EEPROM_NUM_SERVOS][2];
2018-10-31 22:39:49 +01:00
#endif
EEPROM_READ(servo_angles_arr);
2018-10-31 22:39:49 +01:00
}
2018-08-07 17:04:46 +02:00
2019-05-26 04:56:47 +02:00
//
// BLTOUCH
//
{
_FIELD_TEST(bltouch_last_written_mode);
#if ENABLED(BLTOUCH)
bool &bltouch_last_written_mode = bltouch.last_written_mode;
#else
bool bltouch_last_written_mode;
#endif
EEPROM_READ(bltouch_last_written_mode);
}
2017-11-04 21:34:24 +01:00
//
// DELTA Geometry or Dual Endstops offsets
//
2018-10-31 22:39:49 +01:00
{
#if ENABLED(DELTA)
2017-11-04 21:34:24 +01:00
2018-10-31 22:39:49 +01:00
_FIELD_TEST(delta_height);
2018-01-10 01:33:44 +01:00
2018-10-31 22:39:49 +01:00
EEPROM_READ(delta_height); // 1 float
EEPROM_READ(delta_endstop_adj); // 3 floats
EEPROM_READ(delta_radius); // 1 float
EEPROM_READ(delta_diagonal_rod); // 1 float
EEPROM_READ(delta_segments_per_second); // 1 float
EEPROM_READ(delta_tower_angle_trim); // 3 floats
2018-01-10 01:33:44 +01:00
#elif EITHER(X_DUAL_ENDSTOPS, Y_DUAL_ENDSTOPS) || Z_MULTI_ENDSTOPS
2018-10-31 22:39:49 +01:00
_FIELD_TEST(x2_endstop_adj);
2018-10-31 22:39:49 +01:00
#if ENABLED(X_DUAL_ENDSTOPS)
EEPROM_READ(endstops.x2_endstop_adj); // 1 float
#else
EEPROM_READ(dummy);
#endif
#if ENABLED(Y_DUAL_ENDSTOPS)
EEPROM_READ(endstops.y2_endstop_adj); // 1 float
#else
EEPROM_READ(dummy);
#endif
#if Z_MULTI_ENDSTOPS
EEPROM_READ(endstops.z2_endstop_adj); // 1 float
#else
EEPROM_READ(dummy);
#endif
#if ENABLED(Z_TRIPLE_ENDSTOPS)
EEPROM_READ(endstops.z3_endstop_adj); // 1 float
#else
EEPROM_READ(dummy);
#endif
2018-01-10 01:33:44 +01:00
#endif
2018-10-31 22:39:49 +01:00
}
2016-10-29 01:55:42 +02:00
2017-11-04 21:34:24 +01:00
//
// LCD Preheat settings
//
2018-10-31 22:39:49 +01:00
{
_FIELD_TEST(ui_preheat_hotend_temp);
2017-11-04 21:34:24 +01:00
2019-09-10 09:20:49 +02:00
#if HOTENDS && HAS_LCD_MENU
int16_t (&ui_preheat_hotend_temp)[2] = ui.preheat_hotend_temp,
(&ui_preheat_bed_temp)[2] = ui.preheat_bed_temp;
uint8_t (&ui_preheat_fan_speed)[2] = ui.preheat_fan_speed;
#else
int16_t ui_preheat_hotend_temp[2], ui_preheat_bed_temp[2];
uint8_t ui_preheat_fan_speed[2];
2018-10-31 22:39:49 +01:00
#endif
EEPROM_READ(ui_preheat_hotend_temp); // 2 floats
EEPROM_READ(ui_preheat_bed_temp); // 2 floats
EEPROM_READ(ui_preheat_fan_speed); // 2 floats
2018-10-31 22:39:49 +01:00
}
2016-10-29 01:55:42 +02:00
2017-11-04 21:34:24 +01:00
//
// Hotend PID
//
{
HOTEND_LOOP() {
2019-11-26 10:34:43 +01:00
PIDCF_t pidcf;
EEPROM_READ(pidcf);
#if ENABLED(PIDTEMP)
2019-11-26 10:34:43 +01:00
if (!validating && pidcf.Kp != DUMMY_PID_VALUE) {
// Scale PID values since EEPROM values are unscaled
2019-11-26 10:34:43 +01:00
PID_PARAM(Kp, e) = pidcf.Kp;
PID_PARAM(Ki, e) = scalePID_i(pidcf.Ki);
PID_PARAM(Kd, e) = scalePID_d(pidcf.Kd);
#if ENABLED(PID_EXTRUSION_SCALING)
2019-11-26 10:34:43 +01:00
PID_PARAM(Kc, e) = pidcf.Kc;
#endif
#if ENABLED(PID_FAN_SCALING)
PID_PARAM(Kf, e) = pidcf.Kf;
#endif
}
#endif
2016-10-29 01:55:42 +02:00
}
}
2016-10-29 01:55:42 +02:00
2017-11-04 21:34:24 +01:00
//
// PID Extrusion Scaling
//
{
_FIELD_TEST(lpq_len);
#if ENABLED(PID_EXTRUSION_SCALING)
EEPROM_READ(thermalManager.lpq_len);
#else
int16_t lpq_len;
EEPROM_READ(lpq_len);
#endif
}
2016-10-29 01:55:42 +02:00
2017-11-04 21:34:24 +01:00
//
// Heated Bed PID
//
{
PID_t pid;
EEPROM_READ(pid);
#if ENABLED(PIDTEMPBED)
if (!validating && pid.Kp != DUMMY_PID_VALUE) {
// Scale PID values since EEPROM values are unscaled
thermalManager.temp_bed.pid.Kp = pid.Kp;
thermalManager.temp_bed.pid.Ki = scalePID_i(pid.Ki);
thermalManager.temp_bed.pid.Kd = scalePID_d(pid.Kd);
}
#endif
}
2016-10-29 01:55:42 +02:00
2019-05-07 01:51:06 +02:00
//
// User-defined Thermistors
//
#if HAS_USER_THERMISTORS
{
_FIELD_TEST(user_thermistor);
EEPROM_READ(thermalManager.user_thermistor);
}
#endif
2017-11-04 21:34:24 +01:00
//
// LCD Contrast
//
{
_FIELD_TEST(lcd_contrast);
int16_t lcd_contrast;
EEPROM_READ(lcd_contrast);
#if HAS_LCD_CONTRAST
ui.set_contrast(lcd_contrast);
#endif
}
2016-10-29 01:55:42 +02:00
2018-11-17 03:47:07 +01:00
//
// Power-Loss Recovery
//
{
_FIELD_TEST(recovery_enabled);
#if ENABLED(POWER_LOSS_RECOVERY)
EEPROM_READ(recovery.enabled);
#else
bool recovery_enabled;
EEPROM_READ(recovery_enabled);
#endif
}
2017-11-04 21:34:24 +01:00
//
// Firmware Retraction
//
{
_FIELD_TEST(fwretract_settings);
2017-11-04 21:34:24 +01:00
#if ENABLED(FWRETRACT)
EEPROM_READ(fwretract.settings);
#else
fwretract_settings_t fwretract_settings;
EEPROM_READ(fwretract_settings);
#endif
#if BOTH(FWRETRACT, FWRETRACT_AUTORETRACT)
EEPROM_READ(fwretract.autoretract_enabled);
#else
bool autoretract_enabled;
EEPROM_READ(autoretract_enabled);
#endif
}
2016-10-29 01:55:42 +02:00
2017-11-04 21:34:24 +01:00
//
// Volumetric & Filament Size
//
{
struct {
bool volumetric_enabled;
float filament_size[EXTRUDERS];
} storage;
_FIELD_TEST(parser_volumetric_enabled);
EEPROM_READ(storage);
#if DISABLED(NO_VOLUMETRICS)
if (!validating) {
parser.volumetric_enabled = storage.volumetric_enabled;
COPY(planner.filament_size, storage.filament_size);
}
#endif
}
2018-03-15 04:03:53 +01:00
2017-11-04 21:34:24 +01:00
//
2018-10-03 09:48:49 +02:00
// TMC Stepper Settings
2017-11-04 21:34:24 +01:00
//
2018-01-10 01:33:44 +01:00
if (!validating) reset_stepper_drivers();
2018-01-10 01:33:44 +01:00
// TMC Stepper Current
{
_FIELD_TEST(tmc_stepper_current);
2018-03-15 04:03:53 +01:00
tmc_stepper_current_t currents;
EEPROM_READ(currents);
2018-03-15 04:03:53 +01:00
#if HAS_TRINAMIC
2018-10-03 18:32:09 +02:00
#define SET_CURR(Q) stepper##Q.rms_current(currents.Q ? currents.Q : Q##_CURRENT)
if (!validating) {
#if AXIS_IS_TMC(X)
SET_CURR(X);
#endif
#if AXIS_IS_TMC(Y)
SET_CURR(Y);
#endif
#if AXIS_IS_TMC(Z)
SET_CURR(Z);
#endif
#if AXIS_IS_TMC(X2)
SET_CURR(X2);
#endif
#if AXIS_IS_TMC(Y2)
SET_CURR(Y2);
#endif
#if AXIS_IS_TMC(Z2)
SET_CURR(Z2);
#endif
#if AXIS_IS_TMC(Z3)
SET_CURR(Z3);
#endif
#if AXIS_IS_TMC(E0)
SET_CURR(E0);
#endif
#if AXIS_IS_TMC(E1)
SET_CURR(E1);
#endif
#if AXIS_IS_TMC(E2)
SET_CURR(E2);
#endif
#if AXIS_IS_TMC(E3)
SET_CURR(E3);
#endif
#if AXIS_IS_TMC(E4)
SET_CURR(E4);
#endif
#if AXIS_IS_TMC(E5)
SET_CURR(E5);
#endif
}
#endif
}
// TMC Hybrid Threshold
{
2018-10-03 09:48:49 +02:00
tmc_hybrid_threshold_t tmc_hybrid_threshold;
_FIELD_TEST(tmc_hybrid_threshold);
2018-03-15 04:03:53 +01:00
EEPROM_READ(tmc_hybrid_threshold);
#if ENABLED(HYBRID_THRESHOLD)
if (!validating) {
#if AXIS_HAS_STEALTHCHOP(X)
stepperX.set_pwm_thrs(tmc_hybrid_threshold.X);
#endif
#if AXIS_HAS_STEALTHCHOP(Y)
stepperY.set_pwm_thrs(tmc_hybrid_threshold.Y);
#endif
#if AXIS_HAS_STEALTHCHOP(Z)
stepperZ.set_pwm_thrs(tmc_hybrid_threshold.Z);
#endif
#if AXIS_HAS_STEALTHCHOP(X2)
stepperX2.set_pwm_thrs(tmc_hybrid_threshold.X2);
#endif
#if AXIS_HAS_STEALTHCHOP(Y2)
stepperY2.set_pwm_thrs(tmc_hybrid_threshold.Y2);
#endif
#if AXIS_HAS_STEALTHCHOP(Z2)
stepperZ2.set_pwm_thrs(tmc_hybrid_threshold.Z2);
#endif
#if AXIS_HAS_STEALTHCHOP(Z3)
stepperZ3.set_pwm_thrs(tmc_hybrid_threshold.Z3);
#endif
#if AXIS_HAS_STEALTHCHOP(E0)
stepperE0.set_pwm_thrs(tmc_hybrid_threshold.E0);
#endif
#if AXIS_HAS_STEALTHCHOP(E1)
stepperE1.set_pwm_thrs(tmc_hybrid_threshold.E1);
#endif
#if AXIS_HAS_STEALTHCHOP(E2)
stepperE2.set_pwm_thrs(tmc_hybrid_threshold.E2);
#endif
#if AXIS_HAS_STEALTHCHOP(E3)
stepperE3.set_pwm_thrs(tmc_hybrid_threshold.E3);
#endif
#if AXIS_HAS_STEALTHCHOP(E4)
stepperE4.set_pwm_thrs(tmc_hybrid_threshold.E4);
#endif
#if AXIS_HAS_STEALTHCHOP(E5)
stepperE5.set_pwm_thrs(tmc_hybrid_threshold.E5);
#endif
}
#endif
}
2017-12-15 22:03:14 +01:00
//
// TMC StallGuard threshold.
// X and X2 use the same value
// Y and Y2 use the same value
// Z, Z2 and Z3 use the same value
//
{
tmc_sgt_t tmc_sgt;
_FIELD_TEST(tmc_sgt);
EEPROM_READ(tmc_sgt);
#if USE_SENSORLESS
if (!validating) {
#ifdef X_STALL_SENSITIVITY
#if AXIS_HAS_STALLGUARD(X)
2019-06-20 22:47:50 +02:00
stepperX.homing_threshold(tmc_sgt.X);
#endif
#if AXIS_HAS_STALLGUARD(X2) && !X2_SENSORLESS
2019-06-20 22:47:50 +02:00
stepperX2.homing_threshold(tmc_sgt.X);
#endif
#endif
#if X2_SENSORLESS
stepperX2.homing_threshold(tmc_sgt.X2);
#endif
#ifdef Y_STALL_SENSITIVITY
#if AXIS_HAS_STALLGUARD(Y)
2019-06-20 22:47:50 +02:00
stepperY.homing_threshold(tmc_sgt.Y);
#endif
#if AXIS_HAS_STALLGUARD(Y2)
2019-06-20 22:47:50 +02:00
stepperY2.homing_threshold(tmc_sgt.Y);
#endif
#endif
#ifdef Z_STALL_SENSITIVITY
#if AXIS_HAS_STALLGUARD(Z)
2019-06-20 22:47:50 +02:00
stepperZ.homing_threshold(tmc_sgt.Z);
#endif
#if AXIS_HAS_STALLGUARD(Z2)
2019-06-20 22:47:50 +02:00
stepperZ2.homing_threshold(tmc_sgt.Z);
#endif
#if AXIS_HAS_STALLGUARD(Z3)
2019-06-20 22:47:50 +02:00
stepperZ3.homing_threshold(tmc_sgt.Z);
#endif
#endif
}
#endif
}
2018-01-10 01:33:44 +01:00
// TMC stepping mode
{
_FIELD_TEST(tmc_stealth_enabled);
tmc_stealth_enabled_t tmc_stealth_enabled;
EEPROM_READ(tmc_stealth_enabled);
#if HAS_TRINAMIC
#define SET_STEPPING_MODE(ST) stepper##ST.stored.stealthChop_enabled = tmc_stealth_enabled.ST; stepper##ST.refresh_stepping_mode();
if (!validating) {
#if AXIS_HAS_STEALTHCHOP(X)
SET_STEPPING_MODE(X);
#endif
#if AXIS_HAS_STEALTHCHOP(Y)
SET_STEPPING_MODE(Y);
#endif
#if AXIS_HAS_STEALTHCHOP(Z)
SET_STEPPING_MODE(Z);
#endif
#if AXIS_HAS_STEALTHCHOP(X2)
SET_STEPPING_MODE(X2);
#endif
#if AXIS_HAS_STEALTHCHOP(Y2)
SET_STEPPING_MODE(Y2);
#endif
#if AXIS_HAS_STEALTHCHOP(Z2)
SET_STEPPING_MODE(Z2);
#endif
#if AXIS_HAS_STEALTHCHOP(Z3)
SET_STEPPING_MODE(Z3);
#endif
#if AXIS_HAS_STEALTHCHOP(E0)
SET_STEPPING_MODE(E0);
#endif
#if AXIS_HAS_STEALTHCHOP(E1)
SET_STEPPING_MODE(E1);
#endif
#if AXIS_HAS_STEALTHCHOP(E2)
SET_STEPPING_MODE(E2);
#endif
#if AXIS_HAS_STEALTHCHOP(E3)
SET_STEPPING_MODE(E3);
#endif
#if AXIS_HAS_STEALTHCHOP(E4)
SET_STEPPING_MODE(E4);
#endif
#if AXIS_HAS_STEALTHCHOP(E5)
SET_STEPPING_MODE(E5);
#endif
}
#endif
}
//
// Linear Advance
//
{
float extruder_advance_K[EXTRUDERS];
_FIELD_TEST(planner_extruder_advance_K);
EEPROM_READ(extruder_advance_K);
#if ENABLED(LIN_ADVANCE)
if (!validating)
COPY(planner.extruder_advance_K, extruder_advance_K);
#endif
}
2017-11-04 21:34:24 +01:00
//
// Motor Current PWM
//
{
uint32_t motor_current_setting[3];
_FIELD_TEST(motor_current_setting);
EEPROM_READ(motor_current_setting);
#if HAS_MOTOR_CURRENT_PWM
if (!validating)
COPY(stepper.motor_current_setting, motor_current_setting);
#endif
}
2017-11-04 22:36:41 +01:00
//
// CNC Coordinate System
//
{
_FIELD_TEST(coordinate_system);
#if ENABLED(CNC_COORDINATE_SYSTEMS)
if (!validating) (void)gcode.select_coordinate_system(-1); // Go back to machine space
EEPROM_READ(gcode.coordinate_system);
#else
2019-09-29 11:25:39 +02:00
xyz_pos_t coordinate_system[MAX_COORDINATE_SYSTEMS];
EEPROM_READ(coordinate_system);
#endif
}
2017-11-04 22:36:41 +01:00
2017-12-01 23:42:23 +01:00
//
// Skew correction factors
//
{
skew_factor_t skew_factor;
_FIELD_TEST(planner_skew_factor);
EEPROM_READ(skew_factor);
#if ENABLED(SKEW_CORRECTION_GCODE)
if (!validating) {
planner.skew_factor.xy = skew_factor.xy;
#if ENABLED(SKEW_CORRECTION_FOR_Z)
planner.skew_factor.xz = skew_factor.xz;
planner.skew_factor.yz = skew_factor.yz;
#endif
}
2017-12-01 23:42:23 +01:00
#endif
}
2017-12-01 23:42:23 +01:00
//
// Advanced Pause filament load & unload lengths
//
2019-09-10 09:20:49 +02:00
#if EXTRUDERS
{
#if DISABLED(ADVANCED_PAUSE_FEATURE)
fil_change_settings_t fc_settings[EXTRUDERS];
#endif
_FIELD_TEST(fc_settings);
EEPROM_READ(fc_settings);
}
2019-09-10 09:20:49 +02:00
#endif
2018-10-08 00:06:14 +02:00
//
// Tool-change settings
2018-10-08 00:06:14 +02:00
//
#if EXTRUDERS > 1
_FIELD_TEST(toolchange_settings);
EEPROM_READ(toolchange_settings);
2018-10-08 00:06:14 +02:00
#endif
//
// Backlash Compensation
//
{
#if ENABLED(BACKLASH_GCODE)
2019-09-29 11:25:39 +02:00
xyz_float_t &backlash_distance_mm = backlash.distance_mm;
2019-05-21 04:34:08 +02:00
uint8_t &backlash_correction = backlash.correction;
#else
float backlash_distance_mm[XYZ];
uint8_t backlash_correction;
#endif
#if ENABLED(BACKLASH_GCODE) && defined(BACKLASH_SMOOTHING_MM)
float &backlash_smoothing_mm = backlash.smoothing_mm;
#else
2019-05-21 04:34:08 +02:00
float backlash_smoothing_mm;
#endif
_FIELD_TEST(backlash_distance_mm);
EEPROM_READ(backlash_distance_mm);
EEPROM_READ(backlash_correction);
EEPROM_READ(backlash_smoothing_mm);
}
//
// Extensible UI User Data
//
#if ENABLED(EXTENSIBLE_UI)
// This is a significant hardware change; don't reserve EEPROM space when not present
{
const char extui_data[ExtUI::eeprom_data_size] = { 0 };
_FIELD_TEST(extui_data);
EEPROM_READ(extui_data);
if (!validating) ExtUI::onLoadSettings(extui_data);
}
#endif
2018-01-05 03:01:25 +01:00
eeprom_error = size_error(eeprom_index - (EEPROM_OFFSET));
if (eeprom_error) {
DEBUG_ECHO_START();
DEBUG_ECHOLNPAIR("Index: ", int(eeprom_index - (EEPROM_OFFSET)), " Size: ", datasize());
2016-10-29 01:55:42 +02:00
}
2018-01-05 03:01:25 +01:00
else if (working_crc != stored_crc) {
eeprom_error = true;
DEBUG_ERROR_START();
DEBUG_ECHOLNPAIR("EEPROM CRC mismatch - (stored) ", stored_crc, " != ", working_crc, " (calculated)!");
2018-01-05 03:01:25 +01:00
}
else if (!validating) {
DEBUG_ECHO_START();
DEBUG_ECHO(version);
DEBUG_ECHOLNPAIR(" stored settings retrieved (", eeprom_index - (EEPROM_OFFSET), " bytes; crc ", (uint32_t)working_crc, ")");
2018-01-05 03:01:25 +01:00
}
2018-05-12 01:06:04 +02:00
if (!validating && !eeprom_error) postprocess();
2016-10-29 01:55:42 +02:00
2017-03-18 16:15:54 +01:00
#if ENABLED(AUTO_BED_LEVELING_UBL)
2018-01-05 02:51:18 +01:00
if (!validating) {
ubl.report_state();
2018-05-12 01:06:04 +02:00
if (!ubl.sanity_check()) {
2019-02-24 05:53:01 +01:00
SERIAL_EOL();
2018-01-05 02:51:18 +01:00
#if ENABLED(EEPROM_CHITCHAT)
ubl.echo_name();
DEBUG_ECHOLNPGM(" initialized.\n");
2018-01-05 02:51:18 +01:00
#endif
}
else {
eeprom_error = true;
#if ENABLED(EEPROM_CHITCHAT)
DEBUG_ECHOPGM("?Can't enable ");
2018-01-05 02:51:18 +01:00
ubl.echo_name();
DEBUG_ECHOLNPGM(".");
2018-01-05 02:51:18 +01:00
#endif
ubl.reset();
}
2017-03-18 16:15:54 +01:00
2018-01-05 02:51:18 +01:00
if (ubl.storage_slot >= 0) {
load_mesh(ubl.storage_slot);
DEBUG_ECHOLNPAIR("Mesh ", ubl.storage_slot, " loaded from storage.");
2018-01-05 02:51:18 +01:00
}
else {
ubl.reset();
2019-09-26 08:15:35 +02:00
DEBUG_ECHOLNPGM("UBL reset");
2018-01-05 02:51:18 +01:00
}
2017-03-18 16:15:54 +01:00
}
#endif
}
#if ENABLED(EEPROM_CHITCHAT) && DISABLED(DISABLE_M503)
2019-02-24 05:53:01 +01:00
if (!validating) report();
2016-10-29 01:55:42 +02:00
#endif
EEPROM_FINISH();
return !eeprom_error;
2016-10-29 01:55:42 +02:00
}
#ifdef ARCHIM2_SPI_FLASH_EEPROM_BACKUP_SIZE
extern bool restoreEEPROM();
#endif
2019-02-24 05:53:01 +01:00
bool MarlinSettings::validate() {
2018-01-05 02:51:18 +01:00
validating = true;
#ifdef ARCHIM2_SPI_FLASH_EEPROM_BACKUP_SIZE
bool success = _load();
2019-11-10 04:17:18 +01:00
if (!success && restoreEEPROM()) {
SERIAL_ECHOLNPGM("Recovered backup EEPROM settings from SPI Flash");
success = _load();
}
#else
2019-11-10 04:17:18 +01:00
const bool success = _load();
#endif
2018-01-05 02:51:18 +01:00
validating = false;
return success;
}
2019-02-24 05:53:01 +01:00
bool MarlinSettings::load() {
if (validate()) {
const bool success = _load();
#if ENABLED(EXTENSIBLE_UI)
ExtUI::onConfigurationStoreRead(success);
#endif
return success;
}
2018-01-05 02:51:18 +01:00
reset();
2019-05-11 23:54:03 +02:00
#if ENABLED(EEPROM_AUTO_INIT)
(void)save();
SERIAL_ECHO_MSG("EEPROM Initialized");
#endif
return false;
2018-01-05 02:51:18 +01:00
}
#if ENABLED(AUTO_BED_LEVELING_UBL)
inline void ubl_invalid_slot(const int s) {
#if ENABLED(EEPROM_CHITCHAT)
DEBUG_ECHOLNPGM("?Invalid slot.");
DEBUG_ECHO(s);
DEBUG_ECHOLNPGM(" mesh slots available.");
#else
UNUSED(s);
#endif
}
2017-05-16 09:34:36 +02:00
const uint16_t MarlinSettings::meshes_end = persistentStore.capacity() - 129; // 128 (+1 because of the change to capacity rather than last valid address)
// is a placeholder for the size of the MAT; the MAT will always
// live at the very end of the eeprom
2018-06-15 22:51:45 +02:00
uint16_t MarlinSettings::meshes_start_index() {
2018-01-05 04:09:56 +01:00
return (datasize() + EEPROM_OFFSET + 32) & 0xFFF8; // Pad the end of configuration data so it can float up
// or down a little bit without disrupting the mesh data
}
2018-01-05 04:09:56 +01:00
uint16_t MarlinSettings::calc_num_meshes() {
return (meshes_end - meshes_start_index()) / sizeof(ubl.z_values);
}
int MarlinSettings::mesh_slot_offset(const int8_t slot) {
return meshes_end - (slot + 1) * sizeof(ubl.z_values);
}
void MarlinSettings::store_mesh(const int8_t slot) {
#if ENABLED(AUTO_BED_LEVELING_UBL)
const int16_t a = calc_num_meshes();
if (!WITHIN(slot, 0, a - 1)) {
ubl_invalid_slot(a);
DEBUG_ECHOLNPAIR("E2END=", persistentStore.capacity() - 1, " meshes_end=", meshes_end, " slot=", slot);
DEBUG_EOL();
return;
}
int pos = mesh_slot_offset(slot);
uint16_t crc = 0;
// Write crc to MAT along with other data, or just tack on to the beginning or end
persistentStore.access_start();
const bool status = persistentStore.write_data(pos, (uint8_t *)&ubl.z_values, sizeof(ubl.z_values), &crc);
persistentStore.access_finish();
2019-02-03 06:32:48 +01:00
if (status) SERIAL_ECHOLNPGM("?Unable to save mesh data.");
else DEBUG_ECHOLNPAIR("Mesh saved in slot ", slot);
#else
// Other mesh types
#endif
}
void MarlinSettings::load_mesh(const int8_t slot, void * const into/*=nullptr*/) {
#if ENABLED(AUTO_BED_LEVELING_UBL)
const int16_t a = settings.calc_num_meshes();
if (!WITHIN(slot, 0, a - 1)) {
ubl_invalid_slot(a);
return;
}
int pos = mesh_slot_offset(slot);
uint16_t crc = 0;
uint8_t * const dest = into ? (uint8_t*)into : (uint8_t*)&ubl.z_values;
persistentStore.access_start();
const uint16_t status = persistentStore.read_data(pos, dest, sizeof(ubl.z_values), &crc);
persistentStore.access_finish();
2019-02-03 06:32:48 +01:00
if (status) SERIAL_ECHOLNPGM("?Unable to load mesh data.");
else DEBUG_ECHOLNPAIR("Mesh loaded from slot ", slot);
EEPROM_FINISH();
#else
// Other mesh types
#endif
}
//void MarlinSettings::delete_mesh() { return; }
//void MarlinSettings::defrag_meshes() { return; }
#endif // AUTO_BED_LEVELING_UBL
#else // !EEPROM_SETTINGS
2019-02-24 05:53:01 +01:00
bool MarlinSettings::save() {
DEBUG_ERROR_MSG("EEPROM disabled");
return false;
}
#endif // !EEPROM_SETTINGS
/**
* M502 - Reset Configuration
*/
2019-02-24 05:53:01 +01:00
void MarlinSettings::reset() {
2016-12-04 05:02:27 +01:00
LOOP_XYZE_N(i) {
2019-09-26 08:28:09 +02:00
planner.settings.max_acceleration_mm_per_s2[i] = pgm_read_dword(&_DMA[ALIM(i, _DMA)]);
planner.settings.axis_steps_per_mm[i] = pgm_read_float(&_DASU[ALIM(i, _DASU)]);
planner.settings.max_feedrate_mm_s[i] = pgm_read_float(&_DMF[ALIM(i, _DMF)]);
}
planner.settings.min_segment_time_us = DEFAULT_MINSEGMENTTIME;
planner.settings.acceleration = DEFAULT_ACCELERATION;
planner.settings.retract_acceleration = DEFAULT_RETRACT_ACCELERATION;
planner.settings.travel_acceleration = DEFAULT_TRAVEL_ACCELERATION;
2019-09-26 08:28:09 +02:00
planner.settings.min_feedrate_mm_s = feedRate_t(DEFAULT_MINIMUMFEEDRATE);
planner.settings.min_travel_feedrate_mm_s = feedRate_t(DEFAULT_MINTRAVELFEEDRATE);
#if HAS_CLASSIC_JERK
#ifndef DEFAULT_XJERK
#define DEFAULT_XJERK 0
#endif
#ifndef DEFAULT_YJERK
#define DEFAULT_YJERK 0
#endif
#ifndef DEFAULT_ZJERK
#define DEFAULT_ZJERK 0
#endif
2019-09-29 11:25:39 +02:00
planner.max_jerk.set(DEFAULT_XJERK, DEFAULT_YJERK, DEFAULT_ZJERK);
#if HAS_CLASSIC_E_JERK
2019-09-29 11:25:39 +02:00
planner.max_jerk.e = DEFAULT_EJERK;
#endif
#endif
#if DISABLED(CLASSIC_JERK)
planner.junction_deviation_mm = float(JUNCTION_DEVIATION_MM);
#endif
#if HAS_SCARA_OFFSET
2019-09-29 11:25:39 +02:00
scara_home_offset.reset();
#elif HAS_HOME_OFFSET
2019-09-29 11:25:39 +02:00
home_offset.reset();
2017-03-05 01:01:33 +01:00
#endif
2018-08-25 04:26:29 +02:00
#if HAS_HOTEND_OFFSET
reset_hotend_offsets();
#endif
//
// Filament Runout Sensor
//
#if HAS_FILAMENT_SENSOR
runout.enabled = true;
runout.reset();
#ifdef FILAMENT_RUNOUT_DISTANCE_MM
runout.set_runout_distance(FILAMENT_RUNOUT_DISTANCE_MM);
#endif
#endif
//
// Tool-change Settings
//
#if EXTRUDERS > 1
#if ENABLED(TOOLCHANGE_FILAMENT_SWAP)
toolchange_settings.swap_length = TOOLCHANGE_FIL_SWAP_LENGTH;
2019-07-14 18:40:58 +02:00
toolchange_settings.extra_prime = TOOLCHANGE_FIL_EXTRA_PRIME;
toolchange_settings.prime_speed = TOOLCHANGE_FIL_SWAP_PRIME_SPEED;
toolchange_settings.retract_speed = TOOLCHANGE_FIL_SWAP_RETRACT_SPEED;
#endif
#if ENABLED(TOOLCHANGE_PARK)
2019-09-29 11:25:39 +02:00
constexpr xyz_pos_t tpxy = TOOLCHANGE_PARK_XY;
toolchange_settings.change_point = tpxy;
#endif
toolchange_settings.z_raise = TOOLCHANGE_ZRAISE;
2018-10-08 00:06:14 +02:00
#endif
#if ENABLED(BACKLASH_GCODE)
backlash.correction = (BACKLASH_CORRECTION) * 255;
2019-09-29 11:25:39 +02:00
constexpr xyz_float_t tmp = BACKLASH_DISTANCE_MM;
backlash.distance_mm = tmp;
#ifdef BACKLASH_SMOOTHING_MM
backlash.smoothing_mm = BACKLASH_SMOOTHING_MM;
#endif
#endif
#if ENABLED(EXTENSIBLE_UI)
ExtUI::onFactoryReset();
#endif
//
// Magnetic Parking Extruder
//
2019-02-06 13:30:53 +01:00
#if ENABLED(MAGNETIC_PARKING_EXTRUDER)
mpe_settings_init();
#endif
//
// Global Leveling
//
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
new_z_fade_height = 0.0;
#endif
2017-05-01 23:13:09 +02:00
#if HAS_LEVELING
2016-12-10 07:17:49 +01:00
reset_bed_level();
2015-03-26 07:06:33 +01:00
#endif
2016-06-15 03:05:20 +02:00
#if HAS_BED_PROBE
2019-09-25 04:29:21 +02:00
constexpr float dpo[XYZ] = NOZZLE_TO_PROBE_OFFSET;
static_assert(COUNT(dpo) == 3, "NOZZLE_TO_PROBE_OFFSET must contain offsets for X, Y, and Z.");
2019-09-25 06:35:49 +02:00
LOOP_XYZ(a) probe_offset[a] = dpo[a];
2015-03-26 07:06:33 +01:00
#endif
2015-03-15 23:18:11 +01:00
2018-08-07 17:04:46 +02:00
//
// Servo Angles
//
#if ENABLED(EDITABLE_SERVO_ANGLES)
COPY(servo_angles, base_servo_angles);
#endif
2018-08-07 17:04:46 +02:00
2019-05-26 04:56:47 +02:00
//
// BLTOUCH
//
//#if ENABLED(BLTOUCH)
// bltouch.last_written_mode;
//#endif
//
// Endstop Adjustments
//
2018-08-07 17:04:46 +02:00
#if ENABLED(DELTA)
2019-09-29 11:25:39 +02:00
const abc_float_t adj = DELTA_ENDSTOP_ADJ, dta = DELTA_TOWER_ANGLE_TRIM;
delta_height = DELTA_HEIGHT;
2019-09-29 11:25:39 +02:00
delta_endstop_adj = adj;
2016-12-10 07:17:49 +01:00
delta_radius = DELTA_RADIUS;
delta_diagonal_rod = DELTA_DIAGONAL_ROD;
delta_segments_per_second = DELTA_SEGMENTS_PER_SECOND;
2019-09-29 11:25:39 +02:00
delta_tower_angle_trim = dta;
#elif EITHER(X_DUAL_ENDSTOPS, Y_DUAL_ENDSTOPS) || Z_MULTI_ENDSTOPS
#if ENABLED(X_DUAL_ENDSTOPS)
endstops.x2_endstop_adj = (
#ifdef X_DUAL_ENDSTOPS_ADJUSTMENT
X_DUAL_ENDSTOPS_ADJUSTMENT
#else
0
#endif
);
#endif
#if ENABLED(Y_DUAL_ENDSTOPS)
endstops.y2_endstop_adj = (
#ifdef Y_DUAL_ENDSTOPS_ADJUSTMENT
Y_DUAL_ENDSTOPS_ADJUSTMENT
#else
0
#endif
);
#endif
#if ENABLED(Z_DUAL_ENDSTOPS)
endstops.z2_endstop_adj = (
#ifdef Z_DUAL_ENDSTOPS_ADJUSTMENT
Z_DUAL_ENDSTOPS_ADJUSTMENT
#else
0
#endif
);
#elif ENABLED(Z_TRIPLE_ENDSTOPS)
endstops.z2_endstop_adj = (
#ifdef Z_TRIPLE_ENDSTOPS_ADJUSTMENT2
Z_TRIPLE_ENDSTOPS_ADJUSTMENT2
#else
0
#endif
);
endstops.z3_endstop_adj = (
#ifdef Z_TRIPLE_ENDSTOPS_ADJUSTMENT3
Z_TRIPLE_ENDSTOPS_ADJUSTMENT3
#else
0
#endif
);
#endif
#endif
//
// Preheat parameters
//
2019-09-10 09:20:49 +02:00
#if HOTENDS && HAS_LCD_MENU
ui.preheat_hotend_temp[0] = PREHEAT_1_TEMP_HOTEND;
ui.preheat_hotend_temp[1] = PREHEAT_2_TEMP_HOTEND;
ui.preheat_bed_temp[0] = PREHEAT_1_TEMP_BED;
ui.preheat_bed_temp[1] = PREHEAT_2_TEMP_BED;
ui.preheat_fan_speed[0] = PREHEAT_1_FAN_SPEED;
ui.preheat_fan_speed[1] = PREHEAT_2_FAN_SPEED;
#endif
//
// Hotend PID
//
#if ENABLED(PIDTEMP)
HOTEND_LOOP() {
PID_PARAM(Kp, e) = float(DEFAULT_Kp);
PID_PARAM(Ki, e) = scalePID_i(DEFAULT_Ki);
PID_PARAM(Kd, e) = scalePID_d(DEFAULT_Kd);
#if ENABLED(PID_EXTRUSION_SCALING)
PID_PARAM(Kc, e) = DEFAULT_Kc;
#endif
2019-11-26 10:34:43 +01:00
#if ENABLED(PID_FAN_SCALING)
PID_PARAM(Kf, e) = DEFAULT_Kf;
#endif
}
#endif
//
// PID Extrusion Scaling
//
#if ENABLED(PID_EXTRUSION_SCALING)
thermalManager.lpq_len = 20; // Default last-position-queue size
#endif
//
// Heated Bed PID
//
#if ENABLED(PIDTEMPBED)
thermalManager.temp_bed.pid.Kp = DEFAULT_bedKp;
thermalManager.temp_bed.pid.Ki = scalePID_i(DEFAULT_bedKi);
thermalManager.temp_bed.pid.Kd = scalePID_d(DEFAULT_bedKd);
2015-04-04 01:38:05 +02:00
#endif
2019-05-07 01:51:06 +02:00
//
// User-Defined Thermistors
//
#if HAS_USER_THERMISTORS
thermalManager.reset_user_thermistors();
#endif
//
// LCD Contrast
//
#if HAS_LCD_CONTRAST
ui.set_contrast(DEFAULT_LCD_CONTRAST);
#endif
//
// Power-Loss Recovery
//
2018-11-17 03:47:07 +01:00
#if ENABLED(POWER_LOSS_RECOVERY)
recovery.enable(true);
#endif
//
// Firmware Retraction
//
#if ENABLED(FWRETRACT)
2017-09-08 05:40:32 +02:00
fwretract.reset();
#endif
//
// Volumetric & Filament Size
//
#if DISABLED(NO_VOLUMETRICS)
parser.volumetric_enabled =
#if ENABLED(VOLUMETRIC_DEFAULT_ON)
true
#else
false
#endif
;
for (uint8_t q = 0; q < COUNT(planner.filament_size); q++)
planner.filament_size[q] = DEFAULT_NOMINAL_FILAMENT_DIA;
#endif
endstops.enable_globally(
#if ENABLED(ENDSTOPS_ALWAYS_ON_DEFAULT)
true
#else
false
#endif
);
2018-03-15 04:03:53 +01:00
reset_stepper_drivers();
//
// Linear Advance
//
#if ENABLED(LIN_ADVANCE)
LOOP_L_N(i, EXTRUDERS) {
planner.extruder_advance_K[i] = LIN_ADVANCE_K;
#if ENABLED(EXTRA_LIN_ADVANCE_K)
saved_extruder_advance_K[i] = LIN_ADVANCE_K;
#endif
}
#endif
//
// Motor Current PWM
//
#if HAS_MOTOR_CURRENT_PWM
constexpr uint32_t tmp_motor_current_setting[3] = PWM_MOTOR_CURRENT;
for (uint8_t q = 3; q--;)
stepper.digipot_current(q, (stepper.motor_current_setting[q] = tmp_motor_current_setting[q]));
#endif
//
// CNC Coordinate System
//
#if ENABLED(CNC_COORDINATE_SYSTEMS)
(void)gcode.select_coordinate_system(-1); // Go back to machine space
#endif
//
// Skew Correction
//
2017-12-01 23:42:23 +01:00
#if ENABLED(SKEW_CORRECTION_GCODE)
planner.skew_factor.xy = XY_SKEW_FACTOR;
2017-12-01 23:42:23 +01:00
#if ENABLED(SKEW_CORRECTION_FOR_Z)
planner.skew_factor.xz = XZ_SKEW_FACTOR;
planner.skew_factor.yz = YZ_SKEW_FACTOR;
2017-12-01 23:42:23 +01:00
#endif
#endif
//
// Advanced Pause filament load & unload lengths
//
#if ENABLED(ADVANCED_PAUSE_FEATURE)
for (uint8_t e = 0; e < EXTRUDERS; e++) {
fc_settings[e].unload_length = FILAMENT_CHANGE_UNLOAD_LENGTH;
fc_settings[e].load_length = FILAMENT_CHANGE_FAST_LOAD_LENGTH;
}
#endif
2017-04-10 04:47:49 +02:00
postprocess();
DEBUG_ECHO_START();
DEBUG_ECHOLNPGM("Hardcoded Default Settings Loaded");
#if ENABLED(EXTENSIBLE_UI)
ExtUI::onFactoryReset();
#endif
}
#if DISABLED(DISABLE_M503)
2019-02-24 05:53:01 +01:00
#define CONFIG_ECHO_START() do{ if (!forReplay) SERIAL_ECHO_START(); }while(0)
#define CONFIG_ECHO_MSG(STR) do{ CONFIG_ECHO_START(); SERIAL_ECHOLNPGM(STR); }while(0)
#define CONFIG_ECHO_HEADING(STR) do{ if (!forReplay) { CONFIG_ECHO_START(); SERIAL_ECHOLNPGM(STR); } }while(0)
#if HAS_TRINAMIC
inline void say_M906(const bool forReplay) { CONFIG_ECHO_START(); SERIAL_ECHOPGM(" M906"); }
#if HAS_STEALTHCHOP
void say_M569(const bool forReplay, const char * const etc=nullptr, const bool newLine = false) {
CONFIG_ECHO_START();
2019-02-24 05:53:01 +01:00
SERIAL_ECHOPGM(" M569 S1");
if (etc) {
2019-02-24 05:53:01 +01:00
SERIAL_CHAR(' ');
serialprintPGM(etc);
}
if (newLine) SERIAL_EOL();
}
#endif
#if ENABLED(HYBRID_THRESHOLD)
inline void say_M913(const bool forReplay) { CONFIG_ECHO_START(); SERIAL_ECHOPGM(" M913"); }
#endif
2018-09-09 21:59:12 +02:00
#if USE_SENSORLESS
inline void say_M914() { SERIAL_ECHOPGM(" M914"); }
#endif
#endif
2018-03-15 04:03:53 +01:00
#if ENABLED(ADVANCED_PAUSE_FEATURE)
inline void say_M603(const bool forReplay) { CONFIG_ECHO_START(); SERIAL_ECHOPGM(" M603 "); }
2018-03-15 04:03:53 +01:00
#endif
2019-02-24 05:53:01 +01:00
inline void say_units(const bool colon) {
serialprintPGM(
2018-05-08 13:29:53 +02:00
#if ENABLED(INCH_MODE_SUPPORT)
parser.linear_unit_factor != 1.0 ? PSTR(" (in)") :
#endif
PSTR(" (mm)")
);
2019-02-24 05:53:01 +01:00
if (colon) SERIAL_ECHOLNPGM(":");
2018-05-08 13:29:53 +02:00
}
2019-02-24 05:53:01 +01:00
void report_M92(const bool echo=true, const int8_t e=-1);
2016-10-29 01:55:42 +02:00
/**
2017-04-10 04:47:49 +02:00
* M503 - Report current settings in RAM
*
2017-04-10 04:47:49 +02:00
* Unless specifically disabled, M503 is available even without EEPROM
2016-10-29 01:55:42 +02:00
*/
2019-02-24 05:53:01 +01:00
void MarlinSettings::report(const bool forReplay) {
/**
* Announce current units, in case inches are being displayed
*/
CONFIG_ECHO_START();
#if ENABLED(INCH_MODE_SUPPORT)
2019-02-24 05:53:01 +01:00
SERIAL_ECHOPGM(" G2");
SERIAL_CHAR(parser.linear_unit_factor == 1.0 ? '1' : '0');
SERIAL_ECHOPGM(" ;");
say_units(false);
#else
2019-02-24 05:53:01 +01:00
SERIAL_ECHOPGM(" G21 ; Units in mm");
say_units(false);
#endif
2019-02-24 05:53:01 +01:00
SERIAL_EOL();
2018-11-08 16:48:09 +01:00
#if HAS_LCD_MENU
2017-05-07 02:41:50 +02:00
// Temperature units - for Ultipanel temperature options
CONFIG_ECHO_START();
2017-05-07 02:41:50 +02:00
#if ENABLED(TEMPERATURE_UNITS_SUPPORT)
2019-02-24 05:53:01 +01:00
SERIAL_ECHOPGM(" M149 ");
SERIAL_CHAR(parser.temp_units_code());
SERIAL_ECHOPGM(" ; Units in ");
serialprintPGM(parser.temp_units_name());
2017-05-07 02:41:50 +02:00
#else
2019-02-24 05:53:01 +01:00
SERIAL_ECHOLNPGM(" M149 C ; Units in Celsius");
2017-05-07 02:41:50 +02:00
#endif
#endif
2019-02-24 05:53:01 +01:00
SERIAL_EOL();
2017-05-26 01:02:29 +02:00
#if DISABLED(NO_VOLUMETRICS)
/**
* Volumetric extrusion M200
*/
if (!forReplay) {
CONFIG_ECHO_START();
2019-02-24 05:53:01 +01:00
SERIAL_ECHOPGM("Filament settings:");
if (parser.volumetric_enabled)
2019-02-24 05:53:01 +01:00
SERIAL_EOL();
else
2019-02-24 05:53:01 +01:00
SERIAL_ECHOLNPGM(" Disabled");
}
CONFIG_ECHO_START();
SERIAL_ECHOLNPAIR(" M200 D", LINEAR_UNIT(planner.filament_size[0]));
#if EXTRUDERS > 1
CONFIG_ECHO_START();
SERIAL_ECHOLNPAIR(" M200 T1 D", LINEAR_UNIT(planner.filament_size[1]));
#if EXTRUDERS > 2
CONFIG_ECHO_START();
SERIAL_ECHOLNPAIR(" M200 T2 D", LINEAR_UNIT(planner.filament_size[2]));
#if EXTRUDERS > 3
CONFIG_ECHO_START();
SERIAL_ECHOLNPAIR(" M200 T3 D", LINEAR_UNIT(planner.filament_size[3]));
#if EXTRUDERS > 4
CONFIG_ECHO_START();
SERIAL_ECHOLNPAIR(" M200 T4 D", LINEAR_UNIT(planner.filament_size[4]));
#if EXTRUDERS > 5
CONFIG_ECHO_START();
SERIAL_ECHOLNPAIR(" M200 T5 D", LINEAR_UNIT(planner.filament_size[5]));
#endif // EXTRUDERS > 5
#endif // EXTRUDERS > 4
#endif // EXTRUDERS > 3
#endif // EXTRUDERS > 2
#endif // EXTRUDERS > 1
if (!parser.volumetric_enabled)
CONFIG_ECHO_MSG(" M200 D0");
#endif // !NO_VOLUMETRICS
CONFIG_ECHO_HEADING("Steps per unit:");
2019-02-24 05:53:01 +01:00
report_M92(!forReplay);
2016-10-29 01:55:42 +02:00
CONFIG_ECHO_HEADING("Maximum feedrates (units/s):");
CONFIG_ECHO_START();
SERIAL_ECHOLNPAIR_P(
PSTR(" M203 X"), LINEAR_UNIT(planner.settings.max_feedrate_mm_s[X_AXIS])
, SP_Y_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Y_AXIS])
, SP_Z_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Z_AXIS])
#if DISABLED(DISTINCT_E_FACTORS)
, SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_feedrate_mm_s[E_AXIS])
#endif
);
2016-12-04 05:02:27 +01:00
#if ENABLED(DISTINCT_E_FACTORS)
CONFIG_ECHO_START();
2016-12-04 05:02:27 +01:00
for (uint8_t i = 0; i < E_STEPPERS; i++) {
SERIAL_ECHOLNPAIR_P(
PSTR(" M203 T"), (int)i
, SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_feedrate_mm_s[E_AXIS_N(i)])
);
2016-12-04 05:02:27 +01:00
}
#endif
CONFIG_ECHO_HEADING("Maximum Acceleration (units/s2):");
CONFIG_ECHO_START();
SERIAL_ECHOLNPAIR_P(
PSTR(" M201 X"), LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[X_AXIS])
, SP_Y_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Y_AXIS])
, SP_Z_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Z_AXIS])
#if DISABLED(DISTINCT_E_FACTORS)
, SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_acceleration_mm_per_s2[E_AXIS])
#endif
);
2016-12-04 05:02:27 +01:00
#if ENABLED(DISTINCT_E_FACTORS)
CONFIG_ECHO_START();
for (uint8_t i = 0; i < E_STEPPERS; i++)
SERIAL_ECHOLNPAIR_P(
PSTR(" M201 T"), (int)i
, SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(i)])
);
2016-12-04 05:02:27 +01:00
#endif
CONFIG_ECHO_HEADING("Acceleration (units/s2): P<print_accel> R<retract_accel> T<travel_accel>");
CONFIG_ECHO_START();
SERIAL_ECHOLNPAIR(
" M204 P", LINEAR_UNIT(planner.settings.acceleration)
, " R", LINEAR_UNIT(planner.settings.retract_acceleration)
, " T", LINEAR_UNIT(planner.settings.travel_acceleration)
);
if (!forReplay) {
CONFIG_ECHO_START();
2019-02-24 05:53:01 +01:00
SERIAL_ECHOPGM("Advanced: B<min_segment_time_us> S<min_feedrate> T<min_travel_feedrate>");
#if DISABLED(CLASSIC_JERK)
2019-02-24 05:53:01 +01:00
SERIAL_ECHOPGM(" J<junc_dev>");
#endif
#if HAS_CLASSIC_JERK
2019-02-24 05:53:01 +01:00
SERIAL_ECHOPGM(" X<max_x_jerk> Y<max_y_jerk> Z<max_z_jerk>");
#if HAS_CLASSIC_E_JERK
2019-02-24 05:53:01 +01:00
SERIAL_ECHOPGM(" E<max_e_jerk>");
#endif
#endif
2019-02-24 05:53:01 +01:00
SERIAL_EOL();
}
CONFIG_ECHO_START();
SERIAL_ECHOLNPAIR_P(
PSTR(" M205 B"), LINEAR_UNIT(planner.settings.min_segment_time_us)
, PSTR(" S"), LINEAR_UNIT(planner.settings.min_feedrate_mm_s)
, PSTR(" T"), LINEAR_UNIT(planner.settings.min_travel_feedrate_mm_s)
#if DISABLED(CLASSIC_JERK)
, PSTR(" J"), LINEAR_UNIT(planner.junction_deviation_mm)
#endif
#if HAS_CLASSIC_JERK
, SP_X_STR, LINEAR_UNIT(planner.max_jerk.x)
, SP_Y_STR, LINEAR_UNIT(planner.max_jerk.y)
, SP_Z_STR, LINEAR_UNIT(planner.max_jerk.z)
#if HAS_CLASSIC_E_JERK
, SP_E_STR, LINEAR_UNIT(planner.max_jerk.e)
#endif
#endif
);
#if HAS_M206_COMMAND
CONFIG_ECHO_HEADING("Home offset:");
CONFIG_ECHO_START();
SERIAL_ECHOLNPAIR_P(
2019-03-16 01:18:34 +01:00
#if IS_CARTESIAN
PSTR(" M206 X"), LINEAR_UNIT(home_offset.x)
, SP_Y_STR, LINEAR_UNIT(home_offset.y)
, SP_Z_STR
#else
PSTR(" M206 Z")
2019-03-16 01:18:34 +01:00
#endif
, LINEAR_UNIT(home_offset.z)
);
2017-03-05 01:01:33 +01:00
#endif
2018-08-25 04:26:29 +02:00
#if HAS_HOTEND_OFFSET
CONFIG_ECHO_HEADING("Hotend offsets:");
CONFIG_ECHO_START();
2016-10-29 01:55:42 +02:00
for (uint8_t e = 1; e < HOTENDS; e++) {
SERIAL_ECHOPAIR_P(
PSTR(" M218 T"), (int)e,
SP_X_STR, LINEAR_UNIT(hotend_offset[e].x),
SP_Y_STR, LINEAR_UNIT(hotend_offset[e].y)
);
SERIAL_ECHOLNPAIR_F_P(SP_Z_STR, LINEAR_UNIT(hotend_offset[e].z), 3);
}
2016-10-29 01:55:42 +02:00
#endif
2018-01-04 04:55:07 +01:00
/**
* Bed Leveling
*/
#if HAS_LEVELING
2018-01-04 04:55:07 +01:00
#if ENABLED(MESH_BED_LEVELING)
CONFIG_ECHO_HEADING("Mesh Bed Leveling:");
2018-01-04 04:55:07 +01:00
#elif ENABLED(AUTO_BED_LEVELING_UBL)
if (!forReplay) {
CONFIG_ECHO_START();
2018-01-04 04:55:07 +01:00
ubl.echo_name();
2019-02-24 05:53:01 +01:00
SERIAL_ECHOLNPGM(":");
2018-01-04 04:55:07 +01:00
}
2019-02-25 03:29:03 +01:00
#elif HAS_ABL_OR_UBL
2018-01-04 04:55:07 +01:00
CONFIG_ECHO_HEADING("Auto Bed Leveling:");
2018-01-04 04:55:07 +01:00
#endif
CONFIG_ECHO_START();
SERIAL_ECHOLNPAIR_P(
PSTR(" M420 S"), planner.leveling_active ? 1 : 0
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
, SP_Z_STR, LINEAR_UNIT(planner.z_fade_height)
#endif
);
2018-01-04 04:55:07 +01:00
#if ENABLED(MESH_BED_LEVELING)
2017-05-16 09:34:36 +02:00
2018-02-25 15:07:48 +01:00
if (leveling_is_valid()) {
for (uint8_t py = 0; py < GRID_MAX_POINTS_Y; py++) {
for (uint8_t px = 0; px < GRID_MAX_POINTS_X; px++) {
CONFIG_ECHO_START();
SERIAL_ECHOPAIR_P(PSTR(" G29 S3 X"), (int)px + 1, SP_Y_STR, (int)py + 1);
SERIAL_ECHOLNPAIR_F_P(SP_Z_STR, LINEAR_UNIT(mbl.z_values[px][py]), 5);
2018-02-25 15:07:48 +01:00
}
2018-01-04 04:55:07 +01:00
}
}
2018-01-04 04:55:07 +01:00
#elif ENABLED(AUTO_BED_LEVELING_UBL)
if (!forReplay) {
2019-02-24 05:53:01 +01:00
SERIAL_EOL();
2018-01-04 04:55:07 +01:00
ubl.report_state();
2019-02-24 05:53:01 +01:00
SERIAL_ECHOLNPAIR("\nActive Mesh Slot: ", ubl.storage_slot);
SERIAL_ECHOLNPAIR("EEPROM can hold ", calc_num_meshes(), " meshes.\n");
2018-01-04 04:55:07 +01:00
}
2019-02-24 05:53:01 +01:00
//ubl.report_current_mesh(); // This is too verbose for large meshes. A better (more terse)
// solution needs to be found.
2018-02-25 15:07:48 +01:00
#elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
if (leveling_is_valid()) {
for (uint8_t py = 0; py < GRID_MAX_POINTS_Y; py++) {
for (uint8_t px = 0; px < GRID_MAX_POINTS_X; px++) {
CONFIG_ECHO_START();
SERIAL_ECHOPAIR(" G29 W I", (int)px, " J", (int)py);
SERIAL_ECHOLNPAIR_F_P(SP_Z_STR, LINEAR_UNIT(z_values[px][py]), 5);
2018-02-25 15:07:48 +01:00
}
}
}
#endif
2018-01-04 04:55:07 +01:00
#endif // HAS_LEVELING
#if ENABLED(EDITABLE_SERVO_ANGLES)
2018-08-25 04:53:42 +02:00
CONFIG_ECHO_HEADING("Servo Angles:");
2018-08-07 17:04:46 +02:00
for (uint8_t i = 0; i < NUM_SERVOS; i++) {
2018-08-25 04:53:42 +02:00
switch (i) {
#if ENABLED(SWITCHING_EXTRUDER)
case SWITCHING_EXTRUDER_SERVO_NR:
#if EXTRUDERS > 3
case SWITCHING_EXTRUDER_E23_SERVO_NR:
#endif
#elif ENABLED(SWITCHING_NOZZLE)
case SWITCHING_NOZZLE_SERVO_NR:
2019-03-17 11:57:25 +01:00
#elif (ENABLED(BLTOUCH) && defined(BLTOUCH_ANGLES)) || (defined(Z_SERVO_ANGLES) && defined(Z_PROBE_SERVO_NR))
2018-08-25 04:53:42 +02:00
case Z_PROBE_SERVO_NR:
#endif
CONFIG_ECHO_START();
SERIAL_ECHOLNPAIR(" M281 P", int(i), " L", servo_angles[i][0], " U", servo_angles[i][1]);
2018-08-25 04:53:42 +02:00
default: break;
}
2018-08-07 17:04:46 +02:00
}
2018-08-25 04:53:42 +02:00
#endif // EDITABLE_SERVO_ANGLES
2018-08-07 17:04:46 +02:00
#if HAS_SCARA_OFFSET
CONFIG_ECHO_HEADING("SCARA settings: S<seg-per-sec> P<theta-psi-offset> T<theta-offset>");
CONFIG_ECHO_START();
SERIAL_ECHOLNPAIR_P(
PSTR(" M665 S"), delta_segments_per_second
, PSTR(" P"), scara_home_offset.a
, PSTR(" T"), scara_home_offset.b
, SP_Z_STR, LINEAR_UNIT(scara_home_offset.z)
);
#elif ENABLED(DELTA)
2017-11-05 15:49:38 +01:00
CONFIG_ECHO_HEADING("Endstop adjustment:");
CONFIG_ECHO_START();
SERIAL_ECHOLNPAIR_P(
PSTR(" M666 X"), LINEAR_UNIT(delta_endstop_adj.a)
, SP_Y_STR, LINEAR_UNIT(delta_endstop_adj.b)
, SP_Z_STR, LINEAR_UNIT(delta_endstop_adj.c)
);
CONFIG_ECHO_HEADING("Delta settings: L<diagonal_rod> R<radius> H<height> S<segments_per_s> XYZ<tower angle corrections>");
CONFIG_ECHO_START();
SERIAL_ECHOLNPAIR_P(
PSTR(" M665 L"), LINEAR_UNIT(delta_diagonal_rod)
, PSTR(" R"), LINEAR_UNIT(delta_radius)
, PSTR(" H"), LINEAR_UNIT(delta_height)
, PSTR(" S"), delta_segments_per_second
, SP_X_STR, LINEAR_UNIT(delta_tower_angle_trim.a)
, SP_Y_STR, LINEAR_UNIT(delta_tower_angle_trim.b)
, SP_Z_STR, LINEAR_UNIT(delta_tower_angle_trim.c)
);
#elif EITHER(X_DUAL_ENDSTOPS, Y_DUAL_ENDSTOPS) || Z_MULTI_ENDSTOPS
2017-11-05 15:49:38 +01:00
CONFIG_ECHO_HEADING("Endstop adjustment:");
CONFIG_ECHO_START();
2019-02-24 05:53:01 +01:00
SERIAL_ECHOPGM(" M666");
#if ENABLED(X_DUAL_ENDSTOPS)
SERIAL_ECHOPAIR_P(SP_X_STR, LINEAR_UNIT(endstops.x2_endstop_adj));
#endif
#if ENABLED(Y_DUAL_ENDSTOPS)
SERIAL_ECHOPAIR_P(SP_Y_STR, LINEAR_UNIT(endstops.y2_endstop_adj));
#endif
#if ENABLED(Z_TRIPLE_ENDSTOPS)
2019-02-24 05:53:01 +01:00
SERIAL_ECHOLNPAIR("S1 Z", LINEAR_UNIT(endstops.z2_endstop_adj));
CONFIG_ECHO_START();
2019-02-24 05:53:01 +01:00
SERIAL_ECHOPAIR(" M666 S2 Z", LINEAR_UNIT(endstops.z3_endstop_adj));
#elif ENABLED(Z_DUAL_ENDSTOPS)
SERIAL_ECHOPAIR_P(SP_Z_STR, LINEAR_UNIT(endstops.z2_endstop_adj));
#endif
2019-02-24 05:53:01 +01:00
SERIAL_EOL();
2017-11-05 15:49:38 +01:00
#endif // [XYZ]_DUAL_ENDSTOPS
2019-09-10 09:20:49 +02:00
#if HOTENDS && HAS_LCD_MENU
2018-11-08 16:48:09 +01:00
CONFIG_ECHO_HEADING("Material heatup parameters:");
for (uint8_t i = 0; i < COUNT(ui.preheat_hotend_temp); i++) {
CONFIG_ECHO_START();
SERIAL_ECHOLNPAIR(
" M145 S", (int)i
, " H", TEMP_UNIT(ui.preheat_hotend_temp[i])
, " B", TEMP_UNIT(ui.preheat_bed_temp[i])
, " F", int(ui.preheat_fan_speed[i])
);
}
2018-11-08 16:48:09 +01:00
#endif
2016-10-29 01:55:42 +02:00
#if HAS_PID_HEATING
CONFIG_ECHO_HEADING("PID settings:");
2016-10-29 01:55:42 +02:00
#if ENABLED(PIDTEMP)
HOTEND_LOOP() {
CONFIG_ECHO_START();
SERIAL_ECHOPAIR_P(
#if HOTENDS > 1 && ENABLED(PID_PARAMS_PER_HOTEND)
PSTR(" M301 E"), e,
PSTR(" P")
#else
PSTR(" M301 P")
#endif
, PID_PARAM(Kp, e)
, PSTR(" I"), unscalePID_i(PID_PARAM(Ki, e))
, PSTR(" D"), unscalePID_d(PID_PARAM(Kd, e))
);
#if ENABLED(PID_EXTRUSION_SCALING)
SERIAL_ECHOPAIR(" C", PID_PARAM(Kc, e));
if (e == 0) SERIAL_ECHOPAIR(" L", thermalManager.lpq_len);
#endif
2019-11-26 10:34:43 +01:00
#if ENABLED(PID_FAN_SCALING)
SERIAL_ECHOPAIR(" F", PID_PARAM(Kf, e));
#endif
SERIAL_EOL();
2016-10-29 01:55:42 +02:00
}
#endif // PIDTEMP
#if ENABLED(PIDTEMPBED)
CONFIG_ECHO_START();
SERIAL_ECHOLNPAIR(
" M304 P", thermalManager.temp_bed.pid.Kp
, " I", unscalePID_i(thermalManager.temp_bed.pid.Ki)
, " D", unscalePID_d(thermalManager.temp_bed.pid.Kd)
);
2016-10-29 01:55:42 +02:00
#endif
#endif // PIDTEMP || PIDTEMPBED
2019-05-07 01:51:06 +02:00
#if HAS_USER_THERMISTORS
CONFIG_ECHO_HEADING("User thermistors:");
for (uint8_t i = 0; i < USER_THERMISTORS; i++)
thermalManager.log_user_thermistor(i, true);
#endif
2016-10-29 01:55:42 +02:00
#if HAS_LCD_CONTRAST
CONFIG_ECHO_HEADING("LCD Contrast:");
CONFIG_ECHO_START();
2019-02-24 05:53:01 +01:00
SERIAL_ECHOLNPAIR(" M250 C", ui.contrast);
#endif
2018-11-17 03:47:07 +01:00
#if ENABLED(POWER_LOSS_RECOVERY)
CONFIG_ECHO_HEADING("Power-Loss Recovery:");
CONFIG_ECHO_START();
2019-02-24 05:53:01 +01:00
SERIAL_ECHOLNPAIR(" M413 S", int(recovery.enabled));
2018-11-17 03:47:07 +01:00
#endif
2016-10-29 01:55:42 +02:00
#if ENABLED(FWRETRACT)
CONFIG_ECHO_HEADING("Retract: S<length> F<units/m> Z<lift>");
CONFIG_ECHO_START();
SERIAL_ECHOLNPAIR_P(
PSTR(" M207 S"), LINEAR_UNIT(fwretract.settings.retract_length)
, PSTR(" W"), LINEAR_UNIT(fwretract.settings.swap_retract_length)
, PSTR(" F"), LINEAR_UNIT(MMS_TO_MMM(fwretract.settings.retract_feedrate_mm_s))
, SP_Z_STR, LINEAR_UNIT(fwretract.settings.retract_zraise)
);
CONFIG_ECHO_HEADING("Recover: S<length> F<units/m>");
CONFIG_ECHO_START();
SERIAL_ECHOLNPAIR(
" M208 S", LINEAR_UNIT(fwretract.settings.retract_recover_extra)
, " W", LINEAR_UNIT(fwretract.settings.swap_retract_recover_extra)
2019-09-26 08:28:09 +02:00
, " F", LINEAR_UNIT(MMS_TO_MMM(fwretract.settings.retract_recover_feedrate_mm_s))
);
#if ENABLED(FWRETRACT_AUTORETRACT)
CONFIG_ECHO_HEADING("Auto-Retract: S=0 to disable, 1 to interpret E-only moves as retract/recover");
CONFIG_ECHO_START();
2019-02-24 05:53:01 +01:00
SERIAL_ECHOLNPAIR(" M209 S", fwretract.autoretract_enabled ? 1 : 0);
#endif // FWRETRACT_AUTORETRACT
#endif // FWRETRACT
2016-10-29 01:55:42 +02:00
/**
* Probe Offset
2016-10-29 01:55:42 +02:00
*/
#if HAS_BED_PROBE
if (!forReplay) {
CONFIG_ECHO_START();
2019-02-24 05:53:01 +01:00
SERIAL_ECHOPGM("Z-Probe Offset");
say_units(true);
2016-10-29 01:55:42 +02:00
}
CONFIG_ECHO_START();
SERIAL_ECHOLNPAIR_P(PSTR(" M851 X"), LINEAR_UNIT(probe_offset.x),
SP_Y_STR, LINEAR_UNIT(probe_offset.y),
SP_Z_STR, LINEAR_UNIT(probe_offset.z));
2016-10-29 01:55:42 +02:00
#endif
2017-12-01 23:42:23 +01:00
/**
* Bed Skew Correction
*/
#if ENABLED(SKEW_CORRECTION_GCODE)
CONFIG_ECHO_HEADING("Skew Factor: ");
CONFIG_ECHO_START();
2017-12-01 23:42:23 +01:00
#if ENABLED(SKEW_CORRECTION_FOR_Z)
2019-02-24 05:53:01 +01:00
SERIAL_ECHOPAIR_F(" M852 I", LINEAR_UNIT(planner.skew_factor.xy), 6);
SERIAL_ECHOPAIR_F(" J", LINEAR_UNIT(planner.skew_factor.xz), 6);
SERIAL_ECHOLNPAIR_F(" K", LINEAR_UNIT(planner.skew_factor.yz), 6);
2018-03-15 04:03:53 +01:00
#else
2019-02-24 05:53:01 +01:00
SERIAL_ECHOLNPAIR_F(" M852 S", LINEAR_UNIT(planner.skew_factor.xy), 6);
2017-12-01 23:42:23 +01:00
#endif
#endif
2018-01-04 04:55:07 +01:00
#if HAS_TRINAMIC
2018-03-15 04:03:53 +01:00
/**
2018-10-03 09:48:49 +02:00
* TMC stepper driver current
2018-03-15 04:03:53 +01:00
*/
CONFIG_ECHO_HEADING("Stepper driver current:");
#if AXIS_IS_TMC(X) || AXIS_IS_TMC(Y) || AXIS_IS_TMC(Z)
say_M906(forReplay);
2019-12-02 05:23:19 +01:00
#if AXIS_IS_TMC(X)
SERIAL_ECHOPAIR_P(SP_X_STR, stepperX.getMilliamps());
#endif
#if AXIS_IS_TMC(Y)
SERIAL_ECHOPAIR_P(SP_Y_STR, stepperY.getMilliamps());
#endif
#if AXIS_IS_TMC(Z)
SERIAL_ECHOPAIR_P(SP_Z_STR, stepperZ.getMilliamps());
#endif
SERIAL_EOL();
#endif
2018-10-03 09:48:49 +02:00
#if AXIS_IS_TMC(X2) || AXIS_IS_TMC(Y2) || AXIS_IS_TMC(Z2)
say_M906(forReplay);
2019-02-24 05:53:01 +01:00
SERIAL_ECHOPGM(" I1");
2019-12-02 05:23:19 +01:00
#if AXIS_IS_TMC(X2)
SERIAL_ECHOPAIR_P(SP_X_STR, stepperX2.getMilliamps());
#endif
#if AXIS_IS_TMC(Y2)
SERIAL_ECHOPAIR_P(SP_Y_STR, stepperY2.getMilliamps());
#endif
#if AXIS_IS_TMC(Z2)
SERIAL_ECHOPAIR_P(SP_Z_STR, stepperZ2.getMilliamps());
#endif
SERIAL_EOL();
#endif
2018-10-03 09:48:49 +02:00
#if AXIS_IS_TMC(Z3)
say_M906(forReplay);
2019-02-24 05:53:01 +01:00
SERIAL_ECHOLNPAIR(" I2 Z", stepperZ3.getMilliamps());
#endif
2018-10-03 09:48:49 +02:00
#if AXIS_IS_TMC(E0)
say_M906(forReplay);
2019-02-24 05:53:01 +01:00
SERIAL_ECHOLNPAIR(" T0 E", stepperE0.getMilliamps());
#endif
2018-09-20 00:06:51 +02:00
#if AXIS_IS_TMC(E1)
say_M906(forReplay);
2019-02-24 05:53:01 +01:00
SERIAL_ECHOLNPAIR(" T1 E", stepperE1.getMilliamps());
#endif
2018-09-20 00:06:51 +02:00
#if AXIS_IS_TMC(E2)
say_M906(forReplay);
2019-02-24 05:53:01 +01:00
SERIAL_ECHOLNPAIR(" T2 E", stepperE2.getMilliamps());
#endif
2018-09-20 00:06:51 +02:00
#if AXIS_IS_TMC(E3)
say_M906(forReplay);
2019-02-24 05:53:01 +01:00
SERIAL_ECHOLNPAIR(" T3 E", stepperE3.getMilliamps());
#endif
2018-09-20 00:06:51 +02:00
#if AXIS_IS_TMC(E4)
say_M906(forReplay);
2019-02-24 05:53:01 +01:00
SERIAL_ECHOLNPAIR(" T4 E", stepperE4.getMilliamps());
#endif
2018-09-20 00:06:51 +02:00
#if AXIS_IS_TMC(E5)
say_M906(forReplay);
2019-02-24 05:53:01 +01:00
SERIAL_ECHOLNPAIR(" T5 E", stepperE5.getMilliamps());
#endif
2019-02-24 05:53:01 +01:00
SERIAL_EOL();
2017-12-15 22:03:14 +01:00
2018-03-15 04:03:53 +01:00
/**
2018-10-03 09:48:49 +02:00
* TMC Hybrid Threshold
2018-03-15 04:03:53 +01:00
*/
#if ENABLED(HYBRID_THRESHOLD)
CONFIG_ECHO_HEADING("Hybrid Threshold:");
2018-10-03 09:48:49 +02:00
#if AXIS_HAS_STEALTHCHOP(X) || AXIS_HAS_STEALTHCHOP(Y) || AXIS_HAS_STEALTHCHOP(Z)
say_M913(forReplay);
#endif
2018-10-03 09:48:49 +02:00
#if AXIS_HAS_STEALTHCHOP(X)
SERIAL_ECHOPAIR_P(SP_X_STR, stepperX.get_pwm_thrs());
#endif
2018-10-03 09:48:49 +02:00
#if AXIS_HAS_STEALTHCHOP(Y)
SERIAL_ECHOPAIR_P(SP_Y_STR, stepperY.get_pwm_thrs());
#endif
2018-10-03 09:48:49 +02:00
#if AXIS_HAS_STEALTHCHOP(Z)
SERIAL_ECHOPAIR_P(SP_Z_STR, stepperZ.get_pwm_thrs());
#endif
2018-10-03 09:48:49 +02:00
#if AXIS_HAS_STEALTHCHOP(X) || AXIS_HAS_STEALTHCHOP(Y) || AXIS_HAS_STEALTHCHOP(Z)
2019-02-24 05:53:01 +01:00
SERIAL_EOL();
#endif
2018-10-03 09:48:49 +02:00
#if AXIS_HAS_STEALTHCHOP(X2) || AXIS_HAS_STEALTHCHOP(Y2) || AXIS_HAS_STEALTHCHOP(Z2)
say_M913(forReplay);
2019-02-24 05:53:01 +01:00
SERIAL_ECHOPGM(" I1");
#endif
2018-10-03 09:48:49 +02:00
#if AXIS_HAS_STEALTHCHOP(X2)
SERIAL_ECHOPAIR_P(SP_X_STR, stepperX2.get_pwm_thrs());
#endif
2018-10-03 09:48:49 +02:00
#if AXIS_HAS_STEALTHCHOP(Y2)
SERIAL_ECHOPAIR_P(SP_Y_STR, stepperY2.get_pwm_thrs());
#endif
2018-10-03 09:48:49 +02:00
#if AXIS_HAS_STEALTHCHOP(Z2)
SERIAL_ECHOPAIR_P(SP_Z_STR, stepperZ2.get_pwm_thrs());
#endif
2018-10-03 09:48:49 +02:00
#if AXIS_HAS_STEALTHCHOP(X2) || AXIS_HAS_STEALTHCHOP(Y2) || AXIS_HAS_STEALTHCHOP(Z2)
2019-02-24 05:53:01 +01:00
SERIAL_EOL();
#endif
2018-10-03 09:48:49 +02:00
#if AXIS_HAS_STEALTHCHOP(Z3)
say_M913(forReplay);
SERIAL_ECHOLNPAIR(" I2 Z", stepperZ3.get_pwm_thrs());
#endif
2018-10-03 09:48:49 +02:00
#if AXIS_HAS_STEALTHCHOP(E0)
say_M913(forReplay);
SERIAL_ECHOLNPAIR(" T0 E", stepperE0.get_pwm_thrs());
#endif
2018-10-03 09:48:49 +02:00
#if AXIS_HAS_STEALTHCHOP(E1)
say_M913(forReplay);
SERIAL_ECHOLNPAIR(" T1 E", stepperE1.get_pwm_thrs());
#endif
2018-10-03 09:48:49 +02:00
#if AXIS_HAS_STEALTHCHOP(E2)
say_M913(forReplay);
SERIAL_ECHOLNPAIR(" T2 E", stepperE2.get_pwm_thrs());
#endif
2018-10-03 09:48:49 +02:00
#if AXIS_HAS_STEALTHCHOP(E3)
say_M913(forReplay);
SERIAL_ECHOLNPAIR(" T3 E", stepperE3.get_pwm_thrs());
#endif
2018-10-03 09:48:49 +02:00
#if AXIS_HAS_STEALTHCHOP(E4)
say_M913(forReplay);
SERIAL_ECHOLNPAIR(" T4 E", stepperE4.get_pwm_thrs());
#endif
2018-10-03 09:48:49 +02:00
#if AXIS_HAS_STEALTHCHOP(E5)
say_M913(forReplay);
SERIAL_ECHOLNPAIR(" T5 E", stepperE5.get_pwm_thrs());
#endif
2019-02-24 05:53:01 +01:00
SERIAL_EOL();
#endif // HYBRID_THRESHOLD
2018-03-15 04:03:53 +01:00
/**
2018-10-03 09:48:49 +02:00
* TMC Sensorless homing thresholds
2018-03-15 04:03:53 +01:00
*/
2018-09-09 21:59:12 +02:00
#if USE_SENSORLESS
CONFIG_ECHO_HEADING("StallGuard threshold:");
#if X_SENSORLESS || Y_SENSORLESS || Z_SENSORLESS
CONFIG_ECHO_START();
2019-02-24 05:53:01 +01:00
say_M914();
#if X_SENSORLESS
SERIAL_ECHOPAIR_P(SP_X_STR, stepperX.homing_threshold());
2018-03-15 04:03:53 +01:00
#endif
#if Y_SENSORLESS
SERIAL_ECHOPAIR_P(SP_Y_STR, stepperY.homing_threshold());
#endif
#if Z_SENSORLESS
SERIAL_ECHOPAIR_P(SP_Z_STR, stepperZ.homing_threshold());
2018-03-15 04:03:53 +01:00
#endif
2019-02-24 05:53:01 +01:00
SERIAL_EOL();
#endif
#if X2_SENSORLESS || Y2_SENSORLESS || Z2_SENSORLESS
CONFIG_ECHO_START();
2019-02-24 05:53:01 +01:00
say_M914();
SERIAL_ECHOPGM(" I1");
#if X2_SENSORLESS
SERIAL_ECHOPAIR_P(SP_X_STR, stepperX2.homing_threshold());
#endif
#if Y2_SENSORLESS
SERIAL_ECHOPAIR_P(SP_Y_STR, stepperY2.homing_threshold());
2018-03-15 04:03:53 +01:00
#endif
#if Z2_SENSORLESS
SERIAL_ECHOPAIR_P(SP_Z_STR, stepperZ2.homing_threshold());
#endif
2019-02-24 05:53:01 +01:00
SERIAL_EOL();
#endif
#if Z3_SENSORLESS
CONFIG_ECHO_START();
2019-02-24 05:53:01 +01:00
say_M914();
2019-06-20 22:47:50 +02:00
SERIAL_ECHOLNPAIR(" I2 Z", stepperZ3.homing_threshold());
#endif
2018-09-09 21:59:12 +02:00
#endif // USE_SENSORLESS
2018-03-15 04:03:53 +01:00
/**
* TMC stepping mode
*/
#if HAS_STEALTHCHOP
CONFIG_ECHO_HEADING("Driver stepping mode:");
#if AXIS_HAS_STEALTHCHOP(X)
const bool chop_x = stepperX.get_stealthChop_status();
#else
constexpr bool chop_x = false;
#endif
#if AXIS_HAS_STEALTHCHOP(Y)
const bool chop_y = stepperY.get_stealthChop_status();
#else
constexpr bool chop_y = false;
#endif
#if AXIS_HAS_STEALTHCHOP(Z)
const bool chop_z = stepperZ.get_stealthChop_status();
#else
constexpr bool chop_z = false;
#endif
if (chop_x || chop_y || chop_z) {
say_M569(forReplay);
2019-12-02 05:23:19 +01:00
if (chop_x) SERIAL_ECHO_P(SP_X_STR);
if (chop_y) SERIAL_ECHO_P(SP_Y_STR);
if (chop_z) SERIAL_ECHO_P(SP_Z_STR);
SERIAL_EOL();
}
#if AXIS_HAS_STEALTHCHOP(X2)
const bool chop_x2 = stepperX2.get_stealthChop_status();
#else
constexpr bool chop_x2 = false;
#endif
#if AXIS_HAS_STEALTHCHOP(Y2)
const bool chop_y2 = stepperY2.get_stealthChop_status();
#else
constexpr bool chop_y2 = false;
#endif
#if AXIS_HAS_STEALTHCHOP(Z2)
const bool chop_z2 = stepperZ2.get_stealthChop_status();
#else
constexpr bool chop_z2 = false;
#endif
if (chop_x2 || chop_y2 || chop_z2) {
say_M569(forReplay, PSTR("I1"));
2019-12-02 05:23:19 +01:00
if (chop_x2) SERIAL_ECHO_P(SP_X_STR);
if (chop_y2) SERIAL_ECHO_P(SP_Y_STR);
if (chop_z2) SERIAL_ECHO_P(SP_Z_STR);
SERIAL_EOL();
}
#if AXIS_HAS_STEALTHCHOP(Z3)
if (stepperZ3.get_stealthChop_status()) { say_M569(forReplay, PSTR("I2 Z"), true); }
#endif
#if AXIS_HAS_STEALTHCHOP(E0)
if (stepperE0.get_stealthChop_status()) { say_M569(forReplay, PSTR("T0 E"), true); }
#endif
#if AXIS_HAS_STEALTHCHOP(E1)
if (stepperE1.get_stealthChop_status()) { say_M569(forReplay, PSTR("T1 E"), true); }
#endif
#if AXIS_HAS_STEALTHCHOP(E2)
if (stepperE2.get_stealthChop_status()) { say_M569(forReplay, PSTR("T2 E"), true); }
#endif
#if AXIS_HAS_STEALTHCHOP(E3)
if (stepperE3.get_stealthChop_status()) { say_M569(forReplay, PSTR("T3 E"), true); }
#endif
#if AXIS_HAS_STEALTHCHOP(E4)
if (stepperE4.get_stealthChop_status()) { say_M569(forReplay, PSTR("T4 E"), true); }
#endif
#if AXIS_HAS_STEALTHCHOP(E5)
if (stepperE5.get_stealthChop_status()) { say_M569(forReplay, PSTR("T5 E"), true); }
#endif
#endif // HAS_STEALTHCHOP
2018-03-15 04:03:53 +01:00
#endif // HAS_TRINAMIC
/**
* Linear Advance
*/
#if ENABLED(LIN_ADVANCE)
CONFIG_ECHO_HEADING("Linear Advance:");
CONFIG_ECHO_START();
#if EXTRUDERS < 2
2019-02-24 05:53:01 +01:00
SERIAL_ECHOLNPAIR(" M900 K", planner.extruder_advance_K[0]);
#else
LOOP_L_N(i, EXTRUDERS)
SERIAL_ECHOLNPAIR(" M900 T", int(i), " K", planner.extruder_advance_K[i]);
#endif
#endif
#if HAS_MOTOR_CURRENT_PWM
CONFIG_ECHO_HEADING("Stepper motor currents:");
CONFIG_ECHO_START();
SERIAL_ECHOLNPAIR_P(
PSTR(" M907 X"), stepper.motor_current_setting[0]
, SP_Z_STR, stepper.motor_current_setting[1]
, SP_E_STR, stepper.motor_current_setting[2]
);
#endif
/**
* Advanced Pause filament load & unload lengths
*/
#if ENABLED(ADVANCED_PAUSE_FEATURE)
CONFIG_ECHO_HEADING("Filament load/unload lengths:");
#if EXTRUDERS == 1
say_M603(forReplay);
SERIAL_ECHOLNPAIR("L", LINEAR_UNIT(fc_settings[0].load_length), " U", LINEAR_UNIT(fc_settings[0].unload_length));
#else
#define _ECHO_603(N) do{ say_M603(forReplay); SERIAL_ECHOLNPAIR("T" STRINGIFY(N) " L", LINEAR_UNIT(fc_settings[N].load_length), " U", LINEAR_UNIT(fc_settings[N].unload_length)); }while(0)
_ECHO_603(0);
_ECHO_603(1);
#if EXTRUDERS > 2
_ECHO_603(2);
#if EXTRUDERS > 3
_ECHO_603(3);
#if EXTRUDERS > 4
_ECHO_603(4);
#if EXTRUDERS > 5
_ECHO_603(5);
#endif // EXTRUDERS > 5
#endif // EXTRUDERS > 4
#endif // EXTRUDERS > 3
#endif // EXTRUDERS > 2
#endif // EXTRUDERS == 1
#endif // ADVANCED_PAUSE_FEATURE
2018-10-08 00:06:14 +02:00
#if EXTRUDERS > 1
CONFIG_ECHO_HEADING("Tool-changing:");
CONFIG_ECHO_START();
2018-10-08 00:06:14 +02:00
M217_report(true);
#endif
#if ENABLED(BACKLASH_GCODE)
CONFIG_ECHO_HEADING("Backlash compensation:");
CONFIG_ECHO_START();
SERIAL_ECHOLNPAIR_P(
PSTR(" M425 F"), backlash.get_correction()
, SP_X_STR, LINEAR_UNIT(backlash.distance_mm.x)
, SP_Y_STR, LINEAR_UNIT(backlash.distance_mm.y)
, SP_Z_STR, LINEAR_UNIT(backlash.distance_mm.z)
#ifdef BACKLASH_SMOOTHING_MM
, PSTR(" S"), LINEAR_UNIT(backlash.smoothing_mm)
#endif
);
#endif
#if HAS_FILAMENT_SENSOR
CONFIG_ECHO_HEADING("Filament runout sensor:");
CONFIG_ECHO_START();
SERIAL_ECHOLNPAIR(
" M412 S", int(runout.enabled)
#ifdef FILAMENT_RUNOUT_DISTANCE_MM
, " D", LINEAR_UNIT(runout.runout_distance())
#endif
);
#endif
2016-10-29 01:55:42 +02:00
}
#endif // !DISABLE_M503
#pragma pack(pop)