Skip to content

Commit

Permalink
MarlinUI support for up to 5 Material Presets (MarlinFirmware#18488)
Browse files Browse the repository at this point in the history
- Add `I` preset parameter to `G26`, `M106`, `M140`, and `M190`.
- Extend menu items to permit a string interpolation.
- Keep material names in a list and interpolate in menu items.
- Extend material presets to support up to 5 predefined materials.

Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
  • Loading branch information
2 people authored and albertogg committed Aug 31, 2020
1 parent 3963db4 commit b034167
Show file tree
Hide file tree
Showing 51 changed files with 1,181 additions and 872 deletions.
57 changes: 47 additions & 10 deletions Marlin/src/gcode/bedlevel/G26.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@
*
* H # Hotend Set the Nozzle Temperature. If not specified, a default of 205 C. will be assumed.
*
* I # Preset Heat the Nozzle and Bed based on a Material Preset (if material presets are defined).
*
* F # Filament Used to specify the diameter of the filament being used. If not specified
* 1.75mm filament is assumed. If you are not getting acceptable results by using the
* 'correct' numbers, you can scale this number up or down a little bit to change the amount
Expand Down Expand Up @@ -140,7 +142,7 @@
constexpr float g26_e_axis_feedrate = 0.025;

static MeshFlags circle_flags, horizontal_mesh_line_flags, vertical_mesh_line_flags;
float random_deviation = 0.0;
float g26_random_deviation = 0.0;

static bool g26_retracted = false; // Track the retracted state of the nozzle so mismatched
// retracts/recovers won't result in a bad state.
Expand Down Expand Up @@ -193,7 +195,7 @@ mesh_index_pair find_closest_circle_to_print(const xy_pos_t &pos) {
f += (g26_xy_pos - m).magnitude() / 15.0f;

// Add the specified amount of Random Noise to our search
if (random_deviation > 1.0) f += random(0.0, random_deviation);
if (g26_random_deviation > 1.0) f += random(0.0, g26_random_deviation);

if (f < closest) {
closest = f; // Found a closer un-printed location
Expand Down Expand Up @@ -508,15 +510,35 @@ void GcodeSuite::G26() {
bool g26_continue_with_closest = parser.boolval('C'),
g26_keep_heaters_on = parser.boolval('K');

// Accept 'I' if temperature presets are defined
const uint8_t preset_index = (0
#if PREHEAT_COUNT
+ (parser.seenval('I') ? _MIN(parser.value_byte(), PREHEAT_COUNT - 1) + 1 : 0)
#endif
);

#if HAS_HEATED_BED
if (parser.seenval('B')) {
g26_bed_temp = parser.value_celsius();
if (g26_bed_temp && !WITHIN(g26_bed_temp, 40, BED_MAX_TARGET)) {

// Get a temperature from 'I' or 'B'
int16_t bedtemp = 0;

// Use the 'I' index if temperature presets are defined
#if PREHEAT_COUNT
if (preset_index) bedtemp = ui.material_preset[preset_index - 1].bed_temp;
#endif

// Look for 'B' Bed Temperature
if (parser.seenval('B')) bedtemp = parser.value_celsius();

if (bedtemp) {
if (!WITHIN(bedtemp, 40, BED_MAX_TARGET)) {
SERIAL_ECHOLNPAIR("?Specified bed temperature not plausible (40-", int(BED_MAX_TARGET), "C).");
return;
}
g26_bed_temp = bedtemp;
}
#endif

#endif // HAS_HEATED_BED

if (parser.seenval('L')) {
g26_layer_height = parser.value_linear_units();
Expand Down Expand Up @@ -580,20 +602,34 @@ void GcodeSuite::G26() {

g26_extrusion_multiplier *= g26_filament_diameter * sq(g26_nozzle) / sq(0.3); // Scale up by nozzle size

if (parser.seenval('H')) {
g26_hotend_temp = parser.value_celsius();
if (!WITHIN(g26_hotend_temp, 165, (HEATER_0_MAXTEMP) - (HOTEND_OVERSHOOT))) {
// Get a temperature from 'I' or 'H'
int16_t noztemp = 0;

// Accept 'I' if temperature presets are defined
#if PREHEAT_COUNT
if (preset_index) noztemp = ui.material_preset[preset_index - 1].hotend_temp;
#endif

// Look for 'H' Hotend Temperature
if (parser.seenval('H')) noztemp = parser.value_celsius();

// If any preset or temperature was specified
if (noztemp) {
if (!WITHIN(noztemp, 165, (HEATER_0_MAXTEMP) - (HOTEND_OVERSHOOT))) {
SERIAL_ECHOLNPGM("?Specified nozzle temperature not plausible.");
return;
}
g26_hotend_temp = noztemp;
}

// 'U' to Randomize and optionally set circle deviation
if (parser.seen('U')) {
randomSeed(millis());
// This setting will persist for the next G26
random_deviation = parser.has_value() ? parser.value_float() : 50.0;
g26_random_deviation = parser.has_value() ? parser.value_float() : 50.0;
}

// Get repeat from 'R', otherwise do one full circuit
int16_t g26_repeats;
#if HAS_LCD_MENU
g26_repeats = parser.intval('R', GRID_MAX_POINTS + 1);
Expand All @@ -610,6 +646,7 @@ void GcodeSuite::G26() {
return;
}

// Set a position with 'X' and/or 'Y'. Default: current_position
g26_xy_pos.set(parser.seenval('X') ? RAW_X_POSITION(parser.value_linear_units()) : current_position.x,
parser.seenval('Y') ? RAW_Y_POSITION(parser.value_linear_units()) : current_position.y);
if (!position_is_reachable(g26_xy_pos)) {
Expand Down
76 changes: 65 additions & 11 deletions Marlin/src/gcode/temp/M104_M109.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,12 @@
#endif

/**
* M104: Set hot end temperature
* M104: Set Hotend Temperature target and return immediately
*
* Parameters:
* I<preset> : Material Preset index (if material presets are defined)
* T<index> : Tool index. If omitted, applies to the active tool
* S<target> : The target temperature in current units
*/
void GcodeSuite::M104() {

Expand All @@ -63,8 +68,25 @@ void GcodeSuite::M104() {
if (target_extruder < 0) return;
#endif

if (parser.seenval('S')) {
const int16_t temp = parser.value_celsius();
bool got_temp = false;
int16_t temp = 0;

// Accept 'I' if temperature presets are defined
#if PREHEAT_COUNT
got_temp = parser.seenval('I');
if (got_temp) {
const uint8_t index = parser.value_byte();
temp = ui.material_preset[_MIN(index, PREHEAT_COUNT - 1)].hotend_temp;
}
#endif

// If no 'I' get the temperature from 'S'
if (!got_temp) {
got_temp = parser.seenval('S');
if (got_temp) temp = parser.value_celsius();
}

if (got_temp) {
#if ENABLED(SINGLENOZZLE_STANDBY_TEMP)
singlenozzle_temp[target_extruder] = temp;
if (target_extruder != active_extruder) return;
Expand All @@ -91,10 +113,25 @@ void GcodeSuite::M104() {
}

/**
* M109: Sxxx Wait for hotend(s) to reach temperature. Waits only when heating.
* Rxxx Wait for hotend(s) to reach temperature. Waits when heating and cooling.
* M109: Set Hotend Temperature target and wait
*
* Parameters
* I<preset> : Material Preset index (if material presets are defined)
* T<index> : Tool index. If omitted, applies to the active tool
* S<target> : The target temperature in current units. Wait for heating only.
* R<target> : The target temperature in current units. Wait for heating and cooling.
*
* With PRINTJOB_TIMER_AUTOSTART also start the job timer on heating and stop it if turned off.
* With AUTOTEMP...
* F<factor> : Autotemp Scaling Factor. Set non-zero to enable Auto-temp.
* S<min> : Minimum temperature, in current units.
* B<max> : Maximum temperature, in current units.
*
* Examples
* M109 S100 : Set target to 100°. Wait until the hotend is at or above 100°.
* M109 R150 : Set target to 150°. Wait until the hotend gets close to 150°.
*
* With PRINTJOB_TIMER_AUTOSTART turning on heaters will start the print job timer
* (used by printingIsActive, etc.) and turning off heaters will stop the timer.
*/
void GcodeSuite::M109() {

Expand All @@ -107,10 +144,27 @@ void GcodeSuite::M109() {
if (target_extruder < 0) return;
#endif

const bool no_wait_for_cooling = parser.seenval('S'),
set_temp = no_wait_for_cooling || parser.seenval('R');
if (set_temp) {
const int16_t temp = parser.value_celsius();
bool got_temp = false;
int16_t temp = 0;

// Accept 'I' if temperature presets are defined
#if PREHEAT_COUNT
got_temp = parser.seenval('I');
if (got_temp) {
const uint8_t index = parser.value_byte();
temp = ui.material_preset[_MIN(index, PREHEAT_COUNT - 1)].hotend_temp;
}
#endif

// Get the temperature from 'S' or 'R'
bool no_wait_for_cooling = false;
if (!got_temp) {
no_wait_for_cooling = parser.seenval('S');
got_temp = no_wait_for_cooling || parser.seenval('R');
if (got_temp) temp = int16_t(parser.value_celsius());
}

if (got_temp) {
#if ENABLED(SINGLENOZZLE_STANDBY_TEMP)
singlenozzle_temp[target_extruder] = temp;
if (target_extruder != active_extruder) return;
Expand Down Expand Up @@ -139,7 +193,7 @@ void GcodeSuite::M109() {

TERN_(AUTOTEMP, planner.autotemp_M104_M109());

if (set_temp)
if (got_temp)
(void)thermalManager.wait_for_hotend(target_extruder, no_wait_for_cooling);
}

Expand Down
32 changes: 25 additions & 7 deletions Marlin/src/gcode/temp/M106_M107.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
#include "../../module/motion.h"
#include "../../module/temperature.h"

#if PREHEAT_COUNT
#include "../../lcd/ultralcd.h"
#endif

#if ENABLED(SINGLENOZZLE)
#define _ALT_P active_extruder
#define _CNT_P EXTRUDERS
Expand All @@ -39,6 +43,7 @@
/**
* M106: Set Fan Speed
*
* I<index> Material Preset index (if material presets are defined)
* S<int> Speed between 0-255
* P<index> Fan index, if more than one fan
*
Expand All @@ -50,19 +55,32 @@
* 3-255 = Set the speed for use with T2
*/
void GcodeSuite::M106() {
const uint8_t p = parser.byteval('P', _ALT_P);
const uint8_t pfan = parser.byteval('P', _ALT_P);

if (p < _CNT_P) {
if (pfan < _CNT_P) {

#if ENABLED(EXTRA_FAN_SPEED)
const uint16_t t = parser.intval('T');
if (t > 0) return thermalManager.set_temp_fan_speed(p, t);
if (t > 0) return thermalManager.set_temp_fan_speed(pfan, t);
#endif

const uint16_t dspeed = parser.seen('A') ? thermalManager.fan_speed[active_extruder] : 255;

uint16_t speed = dspeed;

// Accept 'I' if temperature presets are defined
#if PREHEAT_COUNT
const bool got_preset = parser.seenval('I');
if (got_preset) speed = ui.material_preset[_MIN(parser.value_byte(), PREHEAT_COUNT - 1)].fan_speed;
#else
constexpr bool got_preset = false;
#endif
uint16_t d = parser.seen('A') ? thermalManager.fan_speed[active_extruder] : 255;
uint16_t s = parser.ushortval('S', d);
NOMORE(s, 255U);

thermalManager.set_fan_speed(p, s);
if (!got_preset && parser.seenval('S'))
speed = parser.value_ushort();

// Set speed, with constraint
thermalManager.set_fan_speed(pfan, speed);
}
}

Expand Down
70 changes: 60 additions & 10 deletions Marlin/src/gcode/temp/M140_M190.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,33 @@

/**
* M140: Set bed temperature
*
* I<index> : Preset index (if material presets are defined)
* S<target> : The target temperature in current units
*/
void GcodeSuite::M140() {
if (DEBUGGING(DRYRUN)) return;
if (parser.seenval('S')) {
thermalManager.setTargetBed(parser.value_celsius());

bool got_temp = false;
int16_t temp = 0;

// Accept 'I' if temperature presets are defined
#if PREHEAT_COUNT
got_temp = parser.seenval('I');
if (got_temp) {
const uint8_t index = parser.value_byte();
temp = ui.material_preset[_MIN(index, PREHEAT_COUNT - 1)].bed_temp;
}
#endif

// If no 'I' get the temperature from 'S'
if (!got_temp) {
got_temp = parser.seenval('S');
if (got_temp) temp = parser.value_celsius();
}

if (got_temp) {
thermalManager.setTargetBed(temp);

#if ENABLED(PRINTJOB_TIMER_AUTOSTART)
/**
Expand All @@ -65,20 +87,48 @@ void GcodeSuite::M140() {
}

/**
* M190: Sxxx Wait for bed current temp to reach target temp. Waits only when heating
* Rxxx Wait for bed current temp to reach target temp. Waits when heating and cooling
* M190 - Set Bed Temperature target and wait
*
* Parameters:
* I<index> : Preset index (if material presets are defined)
* S<target> : The target temperature in current units. Wait for heating only.
* R<target> : The target temperature in current units. Wait for heating and cooling.
*
* With PRINTJOB_TIMER_AUTOSTART also start the job timer on heating.
* Examples:
* M190 S60 : Set target to 60°. Wait until the bed is at or above 60°.
* M190 R40 : Set target to 40°. Wait until the bed gets close to 40°.
*
* With PRINTJOB_TIMER_AUTOSTART turning on heaters will start the print job timer
* (used by printingIsActive, etc.) and turning off heaters will stop the timer.
*/
void GcodeSuite::M190() {
if (DEBUGGING(DRYRUN)) return;

const bool no_wait_for_cooling = parser.seenval('S');
if (no_wait_for_cooling || parser.seenval('R')) {
thermalManager.setTargetBed(parser.value_celsius());
TERN_(PRINTJOB_TIMER_AUTOSTART, thermalManager.check_timer_autostart(true, false));
bool got_temp = false;
int16_t temp = 0;

// Accept 'I' if temperature presets are defined
#if PREHEAT_COUNT
got_temp = parser.seenval('I');
if (got_temp) {
const uint8_t index = parser.value_byte();
temp = ui.material_preset[_MIN(index, PREHEAT_COUNT - 1)].bed_temp;
}
#endif

// Get the temperature from 'S' or 'R'
bool no_wait_for_cooling = false;
if (!got_temp) {
no_wait_for_cooling = parser.seenval('S');
got_temp = no_wait_for_cooling || parser.seenval('R');
if (got_temp) temp = int16_t(parser.value_celsius());
}
else return;

if (!got_temp) return;

thermalManager.setTargetBed(temp);

TERN_(PRINTJOB_TIMER_AUTOSTART, thermalManager.check_timer_autostart(true, false));

ui.set_status_P(thermalManager.isHeatingBed() ? GET_TEXT(MSG_BED_HEATING) : GET_TEXT(MSG_BED_COOLING));

Expand Down
8 changes: 0 additions & 8 deletions Marlin/src/inc/Conditionals_LCD.h
Original file line number Diff line number Diff line change
Expand Up @@ -589,14 +589,6 @@
#define NUM_SERVOS 0
#endif

#ifndef PREHEAT_1_LABEL
#define PREHEAT_1_LABEL "PLA"
#endif

#ifndef PREHEAT_2_LABEL
#define PREHEAT_2_LABEL "ABS"
#endif

/**
* Set a flag for a servo probe (or BLTouch)
*/
Expand Down
Loading

0 comments on commit b034167

Please sign in to comment.