Skip to content

Commit

Permalink
Simplify with position_shift
Browse files Browse the repository at this point in the history
  • Loading branch information
thinkyhead committed Feb 19, 2023
1 parent 71360b7 commit 3f5d31f
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 150 deletions.
15 changes: 5 additions & 10 deletions Marlin/Configuration_adv.h
Original file line number Diff line number Diff line change
Expand Up @@ -2561,17 +2561,12 @@
//#define EVENT_GCODE_TOOLCHANGE_ALWAYS_RUN // Always execute above G-code sequences. Use with caution!

/**
* Apply hotend offsets to Extra G-code at runtime for T1.
* EVENT_GCODE_TOOLCHANGE_T1 can be tested when T0 is active and directly used in configuration without any manual offset adjustment.
* New hotend offsets are created in the same precision as the offsets in the Extra G-code.
* X0.0 in EVENT_GCODE_TOOLCHANGE_T1 with HOTEND_OFFSET_X { 0.0, 1.345 } will be offset to X1.3
* Consider coordinates for EVENT_GCODE_TOOLCHANGE_Tx as relative to T0
* so that moves in the specified axes are the same for all tools.
*/
//#define EVENT_GCODE_TOOLCHANGE_AUTO_HOTEND_OFFSET
#if ENABLED(EVENT_GCODE_TOOLCHANGE_AUTO_HOTEND_OFFSET)
#define APPLY_HOTEND_X_OFFSET
#define APPLY_HOTEND_Y_OFFSET
//#define APPLY_HOTEND_Z_OFFSET
#endif
//#define TC_GCODE_USE_GLOBAL_X // Use X position relative to Tool 0
//#define TC_GCODE_USE_GLOBAL_Y // Use Y position relative to Tool 0
//#define TC_GCODE_USE_GLOBAL_Z // Use Z position relative to Tool 0

/**
* Tool Sensors detect when tools have been picked up or dropped.
Expand Down
7 changes: 7 additions & 0 deletions Marlin/src/inc/Conditionals_adv.h
Original file line number Diff line number Diff line change
Expand Up @@ -1152,3 +1152,10 @@
#if EITHER(INPUT_SHAPING_X, INPUT_SHAPING_Y)
#define HAS_SHAPING 1
#endif

// Toolchange Event G-code
#if !HAS_MULTI_EXTRUDER || !(defined(EVENT_GCODE_TOOLCHANGE_T0) || defined(EVENT_GCODE_TOOLCHANGE_T1) || defined(EVENT_GCODE_TOOLCHANGE_T2) || defined(EVENT_GCODE_TOOLCHANGE_T3) || defined(EVENT_GCODE_TOOLCHANGE_T4) || defined(EVENT_GCODE_TOOLCHANGE_T5) || defined(EVENT_GCODE_TOOLCHANGE_T6) || defined(EVENT_GCODE_TOOLCHANGE_T7))
#undef TC_GCODE_USE_GLOBAL_X
#undef TC_GCODE_USE_GLOBAL_Y
#undef TC_GCODE_USE_GLOBAL_Z
#endif
6 changes: 6 additions & 0 deletions Marlin/src/inc/SanityCheck.h
Original file line number Diff line number Diff line change
Expand Up @@ -1013,9 +1013,15 @@ static_assert(X_MAX_LENGTH >= X_BED_SIZE, "Movement bounds (X_MIN_POS, X_MAX_POS
#endif
#endif

/**
* Custom Event G-code
*/
#if defined(EVENT_GCODE_SD_ABORT) && DISABLED(NOZZLE_PARK_FEATURE)
static_assert(nullptr == strstr(EVENT_GCODE_SD_ABORT, "G27"), "NOZZLE_PARK_FEATURE is required to use G27 in EVENT_GCODE_SD_ABORT.");
#endif
#if ANY(TC_GCODE_USE_GLOBAL_X, TC_GCODE_USE_GLOBAL_Y, TC_GCODE_USE_GLOBAL_Z) && ENABLED(NO_WORKSPACE_OFFSETS)
#error "TC_GCODE_USE_GLOBAL_* options are incompatible with NO_WORKSPACE_OFFSETS."
#endif

/**
* I2C Position Encoders
Expand Down
176 changes: 37 additions & 139 deletions Marlin/src/module/tool_change.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,6 @@
#define DEBUG_OUT ENABLED(DEBUG_TOOL_CHANGE)
#include "../core/debug_out.h"

#if ENABLED(EVENT_GCODE_TOOLCHANGE_AUTO_HOTEND_OFFSET)
#include "../gcode/parser.h"
#endif

#if HAS_MULTI_EXTRUDER
toolchange_settings_t toolchange_settings; // Initialized by settings.load()
#endif
Expand Down Expand Up @@ -1088,127 +1084,6 @@ void fast_line_to_current(const AxisEnum fr_axis) { _line_to_current(fr_axis, 0.

#endif // TOOLCHANGE_FILAMENT_SWAP

#if ENABLED(EVENT_GCODE_TOOLCHANGE_AUTO_HOTEND_OFFSET)

struct Gcode_param_pos_info {
char *start, *end;
uint8_t whole_len_diff;
float floatValue;
};

int gcode_param_pos_info_sorter(const void *lhs, const void *rhs) {
return (*(Gcode_param_pos_info*)lhs).start - (*(Gcode_param_pos_info*)rhs).start;
}

void apply_hotend_offset_process_subcommands_now(const uint8_t tool, FSTR_P const fgcode) {
PGM_P pgcode = FTOP(fgcode);
char * const saved_cmd = parser.command_ptr; // Save the parser state

for (;;) {
PGM_P const delim = strchr_P(pgcode, '\n'); // Get address of next newline
const size_t len = delim ? delim - pgcode : strlen_P(pgcode); // Get the command length
char cmd[len + 1];
strncpy_P(cmd, pgcode, len); // Copy the command to the stack
cmd[len] = '\0';
parser.parse(cmd); // Parse the current command

const char *params_to_offset = TERN_(APPLY_HOTEND_X_OFFSET, "X") TERN_(APPLY_HOTEND_Y_OFFSET, "Y") TERN_(APPLY_HOTEND_Z_OFFSET, "Z");
const uint8_t num_params_to_offset = strlen(params_to_offset);
float offsets[num_params_to_offset];

Gcode_param_pos_info param_pos_info[num_params_to_offset];

for (uint8_t i = 0; i < num_params_to_offset; i++) {
param_pos_info[i].start = nullptr;

float o;
if (params_to_offset[i] == 'X') o = hotend_offset[tool].x;
OPTCODE(HAS_Y_AXIS, else if (params_to_offset[i] == 'Y') o = hotend_offset[tool].y)
OPTCODE(HAS_Z_AXIS, else if (params_to_offset[i] == 'Z') o = hotend_offset[tool].z)
offsets[i] = o;

char *x_start, *x_end;
uint8_t x_param_len;
if (offsets[i] != 0 && parser.seen(params_to_offset[i])) {
x_start = parser.stringval(params_to_offset[i]);
if (x_start) {
x_end = strchr(x_start, ' ');
if (!x_end) x_end = x_start + strlen(x_start);
x_param_len = x_end - x_start;
char * decimal_ptr = strchr(x_start, '.');
int8_t dec_idx = (decimal_ptr && decimal_ptr < x_end) ? decimal_ptr - x_start : -1;
uint8_t x_integer_part_len = dec_idx > -1 ? dec_idx : x_param_len;

float new_offset_x_val;
uint8_t new_offset_x_integer_part_len, whole_len_diff;
new_offset_x_val = parser.floatval(params_to_offset[i]) + offsets[i];
new_offset_x_integer_part_len = ((int)log10f(abs(new_offset_x_val))) + 1 + (new_offset_x_val < 0 ? 1 : 0); // Add 1 space for units place in integer part and 1 for negative sign if needed
whole_len_diff = new_offset_x_integer_part_len - x_integer_part_len;

param_pos_info[i].start = x_start;
param_pos_info[i].end = x_end;
param_pos_info[i].whole_len_diff = whole_len_diff;
param_pos_info[i].floatValue = new_offset_x_val;

}
}
}

uint8_t new_offset_str_len = strlen(cmd);
for (uint8_t i = 0; i < num_params_to_offset; i++)
new_offset_str_len += param_pos_info[i].whole_len_diff;

// Sort parameter position info array by param start addresses in case they appear out of order
qsort(param_pos_info, num_params_to_offset, sizeof(param_pos_info[0]), gcode_param_pos_info_sorter);

// Copy data into new command string with offset values
char new_cmd[new_offset_str_len + 1];
char *new_cmd_pos = new_cmd;
for (uint8_t i = 0; i < num_params_to_offset; i++) {
// Skip this param if it is not found
if (!param_pos_info[i].start) continue;

// Copy from beginning of gcode to start of first parameter found
if (new_cmd_pos == new_cmd) {
uint8_t before_length = param_pos_info[i].start-cmd;
strncpy(new_cmd_pos, cmd, before_length);
new_cmd_pos += before_length;
}

const uint8_t new_offset_x_param_len = (param_pos_info[i].end - param_pos_info[i].start) + param_pos_info[i].whole_len_diff;
float integral;
bool offset_value_has_dec = modff(param_pos_info[i].floatValue, &integral) != 0;

const uint8_t new_offset_x_integer_part_len = int(log10f(abs(param_pos_info[i].floatValue))) + 1 + (param_pos_info[i].floatValue < 0 ? 1 : 0); // Add 1 space for units place in integer part and 1 for negative sign if needed
const int8_t ldiff = new_offset_x_param_len - new_offset_x_integer_part_len;
const uint8_t frac_len = ldiff > 1 ? ldiff - 1 : 0;

// Print parameter value to current position in cmd
dtostrf(param_pos_info[i].floatValue, -new_offset_x_param_len, offset_value_has_dec ? frac_len : 0, new_cmd_pos);
new_cmd_pos += new_offset_x_param_len;

// Copy from end of current parameter to next parameter
if (num_params_to_offset - i > 1) {
strncpy(new_cmd_pos, param_pos_info[i].end, param_pos_info[i+1].start - param_pos_info[i].end);
new_cmd_pos += param_pos_info[i+1].start - param_pos_info[i].end;
}
else // Copy from end of current paramter to end of original gcode
strcpy(new_cmd_pos, param_pos_info[i].end);
}

// Use original cmd if no parameters were found and offset
if (new_cmd_pos != new_cmd) parser.parse(new_cmd);

gcode.process_parsed_command(true); // Process it (no "ok")

if (!delim) break; // Last command?
pgcode = delim + 1; // Get the next command
}
parser.parse(saved_cmd); // Restore the parser state
}

#endif // EVENT_GCODE_TOOLCHANGE_AUTO_HOTEND_OFFSET

/**
* Perform a tool-change, which may result in moving the
* previous tool out of the way and the new tool into place.
Expand Down Expand Up @@ -1527,41 +1402,64 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) {

TERN_(HAS_FANMUX, fanmux_switch(active_extruder));

#if ENABLED(EVENT_GCODE_TOOLCHANGE_AUTO_HOTEND_OFFSET)
#define PROCESS_TOOLCHANGE_GCODE(N) apply_hotend_offset_process_subcommands_now(N, F(EVENT_GCODE_TOOLCHANGE_T##N))
#else
#define PROCESS_TOOLCHANGE_GCODE(N) gcode.process_subcommands_now(F(EVENT_GCODE_TOOLCHANGE_T##N));
#endif

if (ENABLED(EVENT_GCODE_TOOLCHANGE_ALWAYS_RUN) || !no_move) {

#if ANY(TC_GCODE_USE_GLOBAL_X, TC_GCODE_USE_GLOBAL_Y, TC_GCODE_USE_GLOBAL_Z)
// G0/G1/G2/G3/G5 moves are relative to the active tool.
// Shift the workspace to make custom moves relative to T0.
xyz_pos_t old_position_shift;
if (new_tool > 0) {
old_position_shift = position_shift;
const xyz_pos_t &he = hotend_offset[new_tool];
#if ENABLED(TC_GCODE_USE_GLOBAL_X)
position_shift.x -= he.x; update_workspace_offset(X_AXIS);
#endif
#if ENABLED(TC_GCODE_USE_GLOBAL_Y)
position_shift.y -= he.y; update_workspace_offset(Y_AXIS);
#endif
#if ENABLED(TC_GCODE_USE_GLOBAL_Z)
position_shift.z -= he.z; update_workspace_offset(Z_AXIS);
#endif
}
#endif

switch (new_tool) {
default: break;
#ifdef EVENT_GCODE_TOOLCHANGE_T0
case 0: PROCESS_TOOLCHANGE_GCODE(0); break;
case 0: gcode.process_subcommands_now(F(EVENT_GCODE_TOOLCHANGE_T0)); break;
#endif
#ifdef EVENT_GCODE_TOOLCHANGE_T1
case 1: PROCESS_TOOLCHANGE_GCODE(1); break;
case 1: gcode.process_subcommands_now(F(EVENT_GCODE_TOOLCHANGE_T1)); break;
#endif
#ifdef EVENT_GCODE_TOOLCHANGE_T2
case 2: PROCESS_TOOLCHANGE_GCODE(2); break;
case 2: gcode.process_subcommands_now(F(EVENT_GCODE_TOOLCHANGE_T2)); break;
#endif
#ifdef EVENT_GCODE_TOOLCHANGE_T3
case 3: PROCESS_TOOLCHANGE_GCODE(3); break;
case 3: gcode.process_subcommands_now(F(EVENT_GCODE_TOOLCHANGE_T3)); break;
#endif
#ifdef EVENT_GCODE_TOOLCHANGE_T4
case 4: PROCESS_TOOLCHANGE_GCODE(4); break;
case 4: gcode.process_subcommands_now(F(EVENT_GCODE_TOOLCHANGE_T4)); break;
#endif
#ifdef EVENT_GCODE_TOOLCHANGE_T5
case 5: PROCESS_TOOLCHANGE_GCODE(5); break;
case 5: gcode.process_subcommands_now(F(EVENT_GCODE_TOOLCHANGE_T5)); break;
#endif
#ifdef EVENT_GCODE_TOOLCHANGE_T6
case 6: PROCESS_TOOLCHANGE_GCODE(6); break;
case 6: gcode.process_subcommands_now(F(EVENT_GCODE_TOOLCHANGE_T6)); break;
#endif
#ifdef EVENT_GCODE_TOOLCHANGE_T7
case 7: PROCESS_TOOLCHANGE_GCODE(7); break;
case 7: gcode.process_subcommands_now(F(EVENT_GCODE_TOOLCHANGE_T7)); break;
#endif
}

#if ANY(TC_GCODE_USE_GLOBAL_X, TC_GCODE_USE_GLOBAL_Y, TC_GCODE_USE_GLOBAL_Z)
if (new_tool > 0) {
position_shift = old_position_shift;
TERN_(TC_GCODE_USE_GLOBAL_X, update_workspace_offset(X_AXIS));
TERN_(TC_GCODE_USE_GLOBAL_Y, update_workspace_offset(Y_AXIS));
TERN_(TC_GCODE_USE_GLOBAL_Z, update_workspace_offset(Z_AXIS));
}
#endif

#ifdef EVENT_GCODE_AFTER_TOOLCHANGE
if (TERN1(DUAL_X_CARRIAGE, dual_x_carriage_mode == DXC_AUTO_PARK_MODE))
gcode.process_subcommands_now(F(EVENT_GCODE_AFTER_TOOLCHANGE));
Expand Down
2 changes: 1 addition & 1 deletion buildroot/tests/BIGTREE_GTR_V1_0
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ opt_set MOTHERBOARD BOARD_BTT_GTR_V1_0 SERIAL_PORT -1 \
Z_DRIVER_TYPE A4988 Z2_DRIVER_TYPE A4988 Z3_DRIVER_TYPE A4988 Z4_DRIVER_TYPE A4988 \
DEFAULT_Kp_LIST '{ 22.2, 20.0, 21.0, 19.0, 18.0 }' DEFAULT_Ki_LIST '{ 1.08 }' DEFAULT_Kd_LIST '{ 114.0, 112.0, 110.0, 108.0 }'
opt_enable TOOLCHANGE_FILAMENT_SWAP TOOLCHANGE_MIGRATION_FEATURE TOOLCHANGE_FS_SLOW_FIRST_PRIME TOOLCHANGE_FS_PRIME_FIRST_USED \
PID_PARAMS_PER_HOTEND Z_MULTI_ENDSTOPS EVENT_GCODE_TOOLCHANGE_AUTO_HOTEND_OFFSET
PID_PARAMS_PER_HOTEND Z_MULTI_ENDSTOPS TC_GCODE_USE_GLOBAL_X TC_GCODE_USE_GLOBAL_Y
exec_test $1 $2 "BigTreeTech GTR | 6 Extruders | Quad Z + Endstops" "$3"

restore_configs
Expand Down

0 comments on commit 3f5d31f

Please sign in to comment.