Commit 8e9f3658 authored by MagoKimbra's avatar MagoKimbra

Fix Delta

parent 2fafa5fb
......@@ -50,8 +50,8 @@ uint8_t mk_debug_flags = DEBUG_NONE;
static float feedrate = 1500.0, saved_feedrate;
float current_position[NUM_AXIS] = { 0.0 };
float destination[NUM_AXIS] = { 0.0 };
uint8_t axis_known_position = 0;
uint8_t axis_was_homed = 0;
bool axis_known_position[3] = { false };
bool axis_homed[3] = { false };
bool pos_saved = false;
float stored_position[NUM_POSITON_SLOTS][NUM_AXIS];
......@@ -192,7 +192,6 @@ double printer_usage_filament;
#endif
#if MECH(DELTA)
#define TOWER_1 X_AXIS
#define TOWER_2 Y_AXIS
#define TOWER_3 Z_AXIS
......@@ -223,22 +222,11 @@ double printer_usage_filament;
const float z_probe_deploy_end_location[] = Z_PROBE_DEPLOY_END_LOCATION;
const float z_probe_retract_start_location[] = Z_PROBE_RETRACT_START_LOCATION;
const float z_probe_retract_end_location[] = Z_PROBE_RETRACT_END_LOCATION;
static float saved_position[3] = { 0.0 };
static float saved_positions[7][3] = {
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
};
static float adj_t1_Radius = 0;
static float adj_t2_Radius = 0;
static float adj_t3_Radius = 0;
static float z_offset;
static float bed_level_c, bed_level_x, bed_level_y, bed_level_z;
static float bed_safe_z = 45; //used for initial bed probe safe distance (to avoid crashing into bed)
static float bed_level_ox, bed_level_oy, bed_level_oz;
static int loopcount;
static bool home_all_axis = true;
......@@ -1358,6 +1346,11 @@ static void clean_up_after_endstop_move() {
endstops_hit_on_purpose(); // clear endstop hit flags
}
static void axis_unhomed_error() {
LCD_MESSAGEPGM(MSG_POSITION_UNKNOWN);
ECHO_LM(ER, MSG_POSITION_UNKNOWN);
}
#if MECH(CARTESIAN) || MECH(COREXY) || MECH(COREYX) || MECH(COREXZ) || MECH(COREZX) || MECH(SCARA)
/**
......@@ -1700,8 +1693,8 @@ static void clean_up_after_endstop_move() {
destination[axis] = current_position[axis];
feedrate = 0.0;
endstops_hit_on_purpose(); // clear endstop hit flags
SBI(axis_was_homed, axis);
SBI(axis_known_position, axis);
axis_known_position[axis] = true;
axis_homed[axis] = true;
#if ENABLED(Z_PROBE_SLED)
// bring probe back
......@@ -1774,14 +1767,14 @@ static void clean_up_after_endstop_move() {
// Slow down the feedrate for the next move
set_homing_bump_feedrate(axis);
// Move slowly towards the endstop until triggered
// Move slowly towards the Endstop until triggered
destination[axis] = 2 * home_bump_mm(axis) * axis_home_dir;
line_to_destination();
st_synchronize();
// retrace by the amount specified in endstop_adj
if (endstop_adj[axis] * axis_home_dir < 0) {
enable_endstops(false); // Disable endstops while moving away
enable_endstops(false); // Disable Endstops while moving away
sync_plan_position();
destination[axis] = endstop_adj[axis];
if (DEBUGGING(INFO)) {
......@@ -1790,7 +1783,7 @@ static void clean_up_after_endstop_move() {
}
line_to_destination();
st_synchronize();
enable_endstops(true); // Enable endstops for next homing move
enable_endstops(true); // Enable Endstops for next homing move
}
if (DEBUGGING(INFO)) ECHO_LMV(INFO, " > endstop_adj * axis_home_dir = ", endstop_adj[axis] * axis_home_dir);
......@@ -1804,9 +1797,9 @@ static void clean_up_after_endstop_move() {
destination[axis] = current_position[axis];
feedrate = 0.0;
endstops_hit_on_purpose(); // clear endstop hit flags
SBI(axis_was_homed, axis);
SBI(axis_known_position, axis);
endstops_hit_on_purpose(); // clear Endstop hit flags
axis_known_position[axis] = true;
axis_homed[axis] = true;
}
}
#define HOMEAXIS(LETTER) homeaxis(LETTER##_AXIS)
......@@ -1890,10 +1883,17 @@ static void clean_up_after_endstop_move() {
void deploy_z_probe() {
#if HAS(SERVO_ENDSTOPS)
// Engage Z Servo endstop if enabled
if (servo_endstop_id[Z_AXIS] >= 0) servo[servo_endstop_id[Z_AXIS]].move(servo_endstop_angle[Z_AXIS][0]);
#endif
feedrate = homing_feedrate[X_AXIS];
destination[X_AXIS] = z_probe_deploy_start_location[X_AXIS];
destination[Y_AXIS] = z_probe_deploy_start_location[Y_AXIS];
destination[Z_AXIS] = z_probe_deploy_start_location[Z_AXIS];
prepare_move_raw();
st_synchronize();
// Engage Z Servo endstop if enabled
if (servo_endstop_id[Z_AXIS] >= 0)
servo[servo_endstop_id[Z_AXIS]].move(servo_endstop_angle[Z_AXIS][0]);
#else
feedrate = homing_feedrate[X_AXIS];
destination[X_AXIS] = z_probe_deploy_start_location[X_AXIS];
destination[Y_AXIS] = z_probe_deploy_start_location[Y_AXIS];
......@@ -1912,13 +1912,23 @@ static void clean_up_after_endstop_move() {
destination[Z_AXIS] = z_probe_deploy_start_location[Z_AXIS];
prepare_move_raw();
st_synchronize();
#endif
}
void retract_z_probe() {
#if HAS(SERVO_ENDSTOPS)
feedrate = homing_feedrate[X_AXIS];
//destination[Z_AXIS] = 50;
//prepare_move_raw();
destination[X_AXIS] = z_probe_retract_start_location[X_AXIS];
destination[Y_AXIS] = z_probe_retract_start_location[Y_AXIS];
destination[Z_AXIS] = z_probe_retract_start_location[Z_AXIS];
prepare_move_raw();
st_synchronize();
// Retract Z Servo endstop if enabled
if (servo_endstop_id[Z_AXIS] >= 0)
servo[servo_endstop_id[Z_AXIS]].move(servo_endstop_angle[Z_AXIS][1]);
#else
feedrate = homing_feedrate[X_AXIS];
destination[X_AXIS] = z_probe_retract_start_location[X_AXIS];
destination[Y_AXIS] = z_probe_retract_start_location[Y_AXIS];
destination[Z_AXIS] = z_probe_retract_start_location[Z_AXIS];
......@@ -1937,12 +1947,6 @@ static void clean_up_after_endstop_move() {
destination[Z_AXIS] = z_probe_retract_start_location[Z_AXIS];
prepare_move_raw();
st_synchronize();
#if HAS(SERVO_ENDSTOPS)
// Retract Z Servo endstop if enabled
if (servo_endstop_id[Z_AXIS] >= 0)
// Change the Z servo angle
servo[servo_endstop_id[Z_AXIS]].move(servo_endstop_angle[Z_AXIS][1]);
#endif
}
......@@ -2028,8 +2032,6 @@ static void clean_up_after_endstop_move() {
}
set_delta_constants();
bed_safe_z = 20;
}
int fix_tower_errors() {
......@@ -2164,8 +2166,6 @@ static void clean_up_after_endstop_move() {
adj_r = 0.5;
if (bed_level_c > 0) adj_r = -0.5;
bed_safe_z = Z_RAISE_BETWEEN_PROBINGS - z_probe_offset[Z_AXIS];
do {
delta_radius += adj_r;
set_delta_constants();
......@@ -2190,8 +2190,8 @@ static void clean_up_after_endstop_move() {
if (c_nochange_count > 0) {
delta_radius = nochange_r;
set_delta_constants();
bed_safe_z = Z_RAISE_BETWEEN_PROBINGS - z_probe_offset[Z_AXIS];
}
return true;
}
}
......@@ -2424,7 +2424,7 @@ static void clean_up_after_endstop_move() {
float z_probe() {
feedrate = AUTOCAL_TRAVELRATE * 60;
prepare_move();
prepare_move(true);
st_synchronize();
enable_endstops(true);
......@@ -2440,15 +2440,18 @@ static void clean_up_after_endstop_move() {
enable_endstops(false);
long stop_steps = st_get_position(Z_AXIS);
/*
if (DEBUGGING(INFO)) {
ECHO_LMV(INFO, "start_z = ", start_z);
ECHO_LMV(INFO, "start_steps = ", start_steps);
ECHO_LMV(INFO, "stop_steps = ", stop_steps);
}
*/
float mm = start_z - float(start_steps - stop_steps) / axis_steps_per_unit[Z_AXIS];
current_position[Z_AXIS] = mm;
sync_plan_position_delta();
// Save tower carriage positions for G30 diagnostic reports
saved_position[X_AXIS] = st_get_axis_position_mm(X_AXIS);
saved_position[Y_AXIS] = st_get_axis_position_mm(Y_AXIS);
saved_position[Z_AXIS] = st_get_axis_position_mm(Z_AXIS);
destination[Z_AXIS] = mm + Z_RAISE_BETWEEN_PROBINGS;
prepare_move_raw();
st_synchronize();
......@@ -2516,11 +2519,11 @@ static void clean_up_after_endstop_move() {
float probe_z, probe_bed_array[probe_count], probe_bed_mean = 0;
destination[X_AXIS] = x - z_probe_offset[X_AXIS];
if (destination[X_AXIS] < X_MIN_POS) destination[X_AXIS] = X_MIN_POS;
if (destination[X_AXIS] > X_MAX_POS) destination[X_AXIS] = X_MAX_POS;
NOLESS(destination[X_AXIS], X_MIN_POS);
NOMORE(destination[X_AXIS], X_MAX_POS);
destination[Y_AXIS] = y - z_probe_offset[Y_AXIS];
if (destination[Y_AXIS] < Y_MIN_POS) destination[Y_AXIS] = Y_MIN_POS;
if (destination[Y_AXIS] > Y_MAX_POS) destination[Y_AXIS] = Y_MAX_POS;
NOLESS(destination[Y_AXIS], Y_MIN_POS);
NOMORE(destination[Y_AXIS], Y_MAX_POS);
for(int i = 0; i < probe_count; i++) {
probe_bed_array[i] = z_probe() + z_probe_offset[Z_AXIS];
......@@ -2540,35 +2543,21 @@ static void clean_up_after_endstop_move() {
ECHO_EV(probe_z, 4);
}
bed_safe_z = probe_z + 5;
return probe_z;
}
void bed_probe_all() {
// Do inital move to safe z level above bed
feedrate = AUTOCAL_TRAVELRATE * 60;
destination[Z_AXIS] = bed_safe_z;
prepare_move_raw();
st_synchronize();
// Initial throwaway probe.. used to stabilize probe
bed_level_c = probe_bed(0.0, 0.0);
// Probe all bed positions & store carriage positions
bed_level_z = probe_bed(0.0, bed_radius);
save_carriage_positions(1);
bed_level_oy = probe_bed(-SIN_60 * bed_radius, COS_60 * bed_radius);
save_carriage_positions(2);
bed_level_x = probe_bed(-SIN_60 * bed_radius, -COS_60 * bed_radius);
save_carriage_positions(3);
bed_level_oz = probe_bed(0.0, -bed_radius);
save_carriage_positions(4);
bed_level_y = probe_bed(SIN_60 * bed_radius, -COS_60 * bed_radius);
save_carriage_positions(5);
bed_level_ox = probe_bed(SIN_60 * bed_radius, COS_60 * bed_radius);
save_carriage_positions(6);
bed_level_c = probe_bed(0.0, 0.0);
save_carriage_positions(0);
}
void calibration_report() {
......@@ -2616,11 +2605,6 @@ static void clean_up_after_endstop_move() {
ECHO_E;
}
void save_carriage_positions(int position_num) {
for(uint8_t i = 0; i < 3; i++)
saved_positions[position_num][i] = saved_position[i];
}
void home_delta_axis() {
saved_feedrate = feedrate;
saved_feedrate_multiplier = feedrate_multiplier;
......@@ -2647,7 +2631,7 @@ static void clean_up_after_endstop_move() {
// Destination reached
set_current_to_destination();
// take care of back off and rehome now we are all at the top
// take care of back off and re home now we are all at the top
HOMEAXIS(X);
HOMEAXIS(Y);
HOMEAXIS(Z);
......@@ -2852,9 +2836,8 @@ static void clean_up_after_endstop_move() {
static void dock_sled(bool dock, int offset=0) {
if (DEBUGGING(INFO)) ECHO_LMV(INFO, "dock_sled", dock);
if (axis_known_position & (_BV(X_AXIS)|_BV(Y_AXIS)) != (_BV(X_AXIS)|_BV(Y_AXIS))) {
LCD_MESSAGEPGM(MSG_POSITION_UNKNOWN);
ECHO_LM(DB, MSG_POSITION_UNKNOWN);
if (!axis_homed[X_AXIS] || !axis_homed[Y_AXIS]) {
axis_unhomed_error();
return;
}
......@@ -3588,7 +3571,7 @@ inline void gcode_G28() {
else if (homeZ) { // Don't need to Home Z twice
// Let's see if X and Y are homed
if (axis_was_homed & (_BV(X_AXIS)|_BV(Y_AXIS)) == (_BV(X_AXIS)|_BV(Y_AXIS))) {
if (axis_homed[X_AXIS] && axis_homed[Y_AXIS]) {
// Make sure the probe is within the physical limits
// NOTE: This doesn't necessarily ensure the probe is also within the bed!
......@@ -3623,8 +3606,7 @@ inline void gcode_G28() {
}
}
else {
LCD_MESSAGEPGM(MSG_POSITION_UNKNOWN);
ECHO_LM(DB, MSG_POSITION_UNKNOWN);
axis_unhomed_error();
}
}
if (DEBUGGING(INFO)) ECHO_LM(INFO, "<<< Z_SAFE_HOMING");
......@@ -3727,7 +3709,7 @@ inline void gcode_G28() {
* G29: Detailed Z-Probe, probes the bed at 3 or more points.
* Will fail if the printer has not been homed with G28.
*
* Enhanced G29 Auto Bed Leveling Probe Routine
* Enhanced G29 Auto Bed Levelling Probe Routine
*
* Parameters With AUTO_BED_LEVELING_GRID:
*
......@@ -3743,7 +3725,7 @@ inline void gcode_G28() {
* V Set the verbose level (0-4). Example: "G29 V3"
*
* T Generate a Bed Topology Report. Example: "G29 P5 T" for a detailed report.
* This is useful for manual bed leveling and finding flaws in the bed (to
* This is useful for manual bed levelling and finding flaws in the bed (to
* assist with part placement).
*
* F Set the Front limit of the probing grid
......@@ -3762,10 +3744,9 @@ inline void gcode_G28() {
inline void gcode_G29() {
if (DEBUGGING(INFO)) ECHO_LM(INFO, "gcode_G29 >>>");
// Don't allow auto-leveling without homing first
if (axis_known_position & (_BV(X_AXIS)|_BV(Y_AXIS)) != (_BV(X_AXIS)|_BV(Y_AXIS))) {
LCD_MESSAGEPGM(MSG_POSITION_UNKNOWN);
ECHO_LM(ER, MSG_POSITION_UNKNOWN);
// Don't allow auto-levelling without homing first
if (!axis_homed[X_AXIS] || !axis_homed[Y_AXIS]) {
axis_unhomed_error();
return;
}
......@@ -4141,10 +4122,11 @@ inline void gcode_G28() {
#if HAS(SERVO_ENDSTOPS)
raise_z_for_servo();
#endif
stow_z_probe(); // Retract Z Servo endstop if available
if (DEBUGGING(INFO)) ECHO_LM(INFO, "<<< gcode_G30");
gcode_M114(); // Send end position to RepetierHost
}
#endif // !Z_PROBE_SLED
#endif // AUTO_BED_LEVELING_FEATURE
......@@ -4167,7 +4149,9 @@ inline void gcode_G28() {
saved_feedrate_multiplier = feedrate_multiplier;
feedrate_multiplier = 100;
if (!axis_homed[X_AXIS] || !axis_homed[Y_AXIS] || !axis_homed[Z_AXIS])
home_delta_axis();
deploy_z_probe();
calibrate_print_surface(z_probe_offset[Z_AXIS] + (code_seen(axis_codes[Z_AXIS]) ? code_value() : 0.0));
retract_z_probe();
......@@ -4182,26 +4166,28 @@ inline void gcode_G28() {
/* G30: Delta AutoCalibration
*
* Parameters:
* C Show Carriage positions
*
* X Y: Probe specified X,Y point
* A<precision>: Autocalibration +/- precision
* E: Adjust Endstop
* R: Adjust Endstop & Delta Radius
* I: Adjust Tower
* D: Adjust Diagonal Rod
* T: Adjust Tower Radius
*/
inline void gcode_G30() {
if (DEBUGGING(INFO)) ECHO_LM(INFO, "gcode_G30 >>>");
// Zero the bed level array
saved_feedrate = feedrate;
saved_feedrate_multiplier = feedrate_multiplier;
feedrate_multiplier = 100;
// Reset the bed level array
reset_bed_level();
if (code_seen('C')) {
// Show carriage positions
ECHO_LM(DB, "Carriage Positions for last scan: ");
for(uint8_t i = 0; i < 7; i++) {
ECHO_SMV(DB, "[", saved_positions[i][X_AXIS]);
ECHO_MV(", ", saved_positions[i][Y_AXIS]);
ECHO_MV(", ", saved_positions[i][Z_AXIS]);
ECHO_EM("]");
}
return;
}
// Homing and deploy z probe
if (!axis_homed[X_AXIS] || !axis_homed[Y_AXIS] || !axis_homed[Z_AXIS])
home_delta_axis();
deploy_z_probe();
if (code_seen('X') and code_seen('Y')) {
// Probe specified X,Y point
......@@ -4209,26 +4195,15 @@ inline void gcode_G28() {
float y = code_seen('Y') ? code_value():0.00;
float probe_value;
deploy_z_probe();
probe_value = probe_bed(x, y);
ECHO_SMV(DB, "Bed Z-Height at X:", x);
ECHO_MV(" Y:", y);
ECHO_EMV(" = ", probe_value, 4);
if (DEBUGGING(INFO)) {
ECHO_SMV(INFO, "Carriage Positions: [", saved_position[X_AXIS]);
ECHO_MV(", ", saved_position[Y_AXIS]);
ECHO_MV(", ", saved_position[Z_AXIS]);
ECHO_EM("]");
}
retract_z_probe();
return;
}
saved_feedrate = feedrate;
saved_feedrate_multiplier = feedrate_multiplier;
feedrate_multiplier = 100;
if (code_seen('A')) {
ECHO_LM(DB, "Starting Auto Calibration...");
LCD_MESSAGEPGM("Auto Calibration...");
......@@ -4237,10 +4212,6 @@ inline void gcode_G28() {
ECHO_EM(" mm");
}
home_delta_axis();
deploy_z_probe();
bed_safe_z = current_position[Z_AXIS];
// Probe all points
bed_probe_all();
......@@ -4253,7 +4224,7 @@ inline void gcode_G28() {
iteration ++;
ECHO_LMV(DB, "Iteration: ", iteration);
ECHO_LM(DB, "Checking/Adjusting endstop offsets");
ECHO_LM(DB, "Checking/Adjusting Endstop offsets");
adj_endstops();
bed_probe_all();
......@@ -4271,7 +4242,7 @@ inline void gcode_G28() {
iteration ++;
ECHO_LMV(DB, "Iteration: ", iteration);
ECHO_LM(DB, "Checking/Adjusting endstop offsets");
ECHO_LM(DB, "Checking/Adjusting Endstop offsets");
adj_endstops();
bed_probe_all();
......@@ -4327,10 +4298,10 @@ inline void gcode_G28() {
dr_adjusted = false;
if (DEBUGGING(DEBUG)) {
ECHO_LMV(DEB, "bed_level_c=", bed_level_c, 4);
ECHO_LMV(DEB, "bed_level_x=", bed_level_x, 4);
ECHO_LMV(DEB, "bed_level_y=", bed_level_y, 4);
ECHO_LMV(DEB, "bed_level_z=", bed_level_z, 4);
ECHO_LMV(DEB, "bed_level_c = ", bed_level_c, 4);
ECHO_LMV(DEB, "bed_level_x = ", bed_level_x, 4);
ECHO_LMV(DEB, "bed_level_y = ", bed_level_y, 4);
ECHO_LMV(DEB, "bed_level_z = ", bed_level_z, 4);
}
idle();
......@@ -4346,32 +4317,31 @@ inline void gcode_G28() {
ECHO_LM(DB, "Checking for tower geometry errors..");
if (fix_tower_errors() != 0 ) {
// Tower positions have been changed .. home to endstops
ECHO_LM(DB, "Tower Positions changed .. Homing Endstops");
ECHO_LM(DB, "Tower Positions changed .. Homing");
home_delta_axis();
bed_safe_z = Z_RAISE_BETWEEN_PROBINGS - z_probe_offset[Z_AXIS];
deploy_z_probe();
}
else {
ECHO_LM(DB, "Checking DiagRod Length");
ECHO_LM(DB, "Checking Diagonal Rod Length");
if (adj_diagrod_length() != 0) {
// If diag rod length has been changed .. home to endstops
ECHO_LM(DB, "Diagonal Rod Length changed .. Homing Endstops");
// If diagonal rod length has been changed .. home to endstops
ECHO_LM(DB, "Diagonal Rod Length changed .. Homing");
home_delta_axis();
bed_safe_z = Z_RAISE_BETWEEN_PROBINGS - z_probe_offset[Z_AXIS];
deploy_z_probe();
}
}
bed_safe_z = Z_RAISE_BETWEEN_PROBINGS - z_probe_offset[Z_AXIS];
bed_probe_all();
calibration_report();
}
if (DEBUGGING(DEBUG)) {
ECHO_LMV(DEB, "bed_level_c=", bed_level_c, 4);
ECHO_LMV(DEB, "bed_level_x=", bed_level_x, 4);
ECHO_LMV(DEB, "bed_level_y=", bed_level_y, 4);
ECHO_LMV(DEB, "bed_level_z=", bed_level_z, 4);
ECHO_LMV(DEB, "bed_level_ox=", bed_level_ox, 4);
ECHO_LMV(DEB, "bed_level_oy=", bed_level_oy, 4);
ECHO_LMV(DEB, "bed_level_oz=", bed_level_oz, 4);
ECHO_LMV(DEB, "bed_level_c = ", bed_level_c, 4);
ECHO_LMV(DEB, "bed_level_x = ", bed_level_x, 4);
ECHO_LMV(DEB, "bed_level_y = ", bed_level_y, 4);
ECHO_LMV(DEB, "bed_level_z = ", bed_level_z, 4);
ECHO_LMV(DEB, "bed_level_ox = ", bed_level_ox, 4);
ECHO_LMV(DEB, "bed_level_oy = ", bed_level_oy, 4);
ECHO_LMV(DEB, "bed_level_oz = ", bed_level_oz, 4);
}
} while((bed_level_c < -ac_prec) or (bed_level_c > ac_prec)
or (bed_level_x < -ac_prec) or (bed_level_x > ac_prec)
......@@ -4796,6 +4766,11 @@ inline void gcode_M42() {
inline void gcode_M48() {
if (DEBUGGING(INFO)) ECHO_LM(INFO, "gcode_M48 >>>");
if (!axis_homed[X_AXIS] || !axis_homed[Y_AXIS] || !axis_homed[Z_AXIS]) {
axis_unhomed_error();
return;
}
double sum = 0.0, mean = 0.0, sigma = 0.0, sample_set[50];
uint8_t verbose_level = 1, n_samples = 10, n_legs = 0;
......@@ -6814,18 +6789,18 @@ inline void gcode_M410() { quickStop(); }
/**
* M428: Set home_offset based on the distance between the
* current_position and the nearest "reference point."
* If an axis is past center its endstop position
* If an axis is past center its Endstop position
* is the reference-point. Otherwise it uses 0. This allows
* the Z offset to be set near the bed when using a max endstop.
* the Z offset to be set near the bed when using a max Endstop.
*
* M428 can't be used more than 2cm away from 0 or an endstop.
* M428 can't be used more than 2cm away from 0 or an Endstop.
*
* Use M206 to set these values directly.
*/
inline void gcode_M428() {
bool err = false;
for (uint8_t i = X_AXIS; i <= Z_AXIS; i++) {
if (TEST(axis_known_position, i)) {
if (axis_homed[i]) {
#if MECH(DELTA)
float base = (current_position[i] > (sw_endstop_min[i] + sw_endstop_max[i]) / 2) ? base_home_pos[i] : 0, diff = current_position[i] - base;
#else
......@@ -8269,7 +8244,7 @@ static void report_current_position() {
#if MECH(DELTA) || MECH(SCARA)
inline bool prepare_move_delta(float target[NUM_AXIS]) {
inline bool prepare_move_delta(float target[NUM_AXIS], const bool delta_probe) {
float difference[NUM_AXIS];
float addDistance[NUM_AXIS];
float fractions[NUM_AXIS];
......@@ -8323,7 +8298,7 @@ static void report_current_position() {
#endif
calculate_delta(target);
adjust_delta(target);
if (!delta_probe) adjust_delta(target);
if (DEBUGGING(DEBUG)) {
ECHO_LMV(DEB, "target[X_AXIS]=", target[X_AXIS]);
......@@ -8342,7 +8317,7 @@ static void report_current_position() {
#endif // DELTA || SCARA
#if MECH(SCARA)
inline bool prepare_move_scara(float target[NUM_AXIS]) { return prepare_move_delta(target); }
inline bool prepare_move_scara(float target[NUM_AXIS]) { return prepare_move_delta(target, false); }
#endif
#if ENABLED(DUAL_X_CARRIAGE)
......@@ -8404,7 +8379,11 @@ static void report_current_position() {
* (This may call plan_buffer_line several times to put
* smaller moves into the planner for DELTA or SCARA.)
*/
void prepare_move() {
void prepare_move(
#if MECH(DELTA)
const bool delta_probe /*= false*/
#endif
) {
clamp_to_software_endstops(destination);
refresh_cmd_timeout();
......@@ -8415,7 +8394,7 @@ void prepare_move() {
#if MECH(SCARA)
if (!prepare_move_scara(destination)) return;
#elif MECH(DELTA)
if (!prepare_move_delta(destination)) return;
if (!prepare_move_delta(destination, delta_probe)) return;
#endif
#if ENABLED(DUAL_X_CARRIAGE)
......
......@@ -48,7 +48,6 @@ void ok_to_send();
void calibration_report();
void bed_probe_all();
void set_delta_constants();
void save_carriage_positions(int position_num);
void calculate_delta(float cartesian[3]);
void adjust_delta(float cartesian[3]);
void adj_endstops();
......@@ -71,7 +70,13 @@ void ok_to_send();
void calculate_delta(float cartesian[3]);
void calculate_SCARA_forward_Transform(float f_scara[3]);
#endif
void prepare_move();
void prepare_move(
#if MECH(DELTA)
const bool delta_probe = false
#endif
);
void kill(const char *);
void Stop();
......@@ -130,9 +135,9 @@ extern float home_offset[3];
extern float hotend_offset[3][HOTENDS];
extern float sw_endstop_min[3];
extern float sw_endstop_max[3];
extern bool axis_known_position[3];
extern bool axis_homed[3];
extern float zprobe_zoffset;
extern uint8_t axis_known_position;
extern uint8_t axis_was_homed;
#if HEATER_USES_AD595
extern float ad595_offset[HOTENDS];
......
......@@ -50,9 +50,6 @@
// 18 Japanese utf
// 19 Chinese
#define STRINGIFY_(n) #n
#define STRINGIFY(n) STRINGIFY_(n)
#define PROTOCOL_VERSION "2.0"
#if MB(ULTIMAKER)|| MB(ULTIMAKER_OLD)|| MB(ULTIMAIN_2)
......
......@@ -349,6 +349,21 @@ FORCE_INLINE void _draw_heater_status(int x, int heater) {
#endif
}
FORCE_INLINE void _draw_axis_label(AxisEnum axis, const char *pstr, bool blink) {
if (blink)
lcd_printPGM(pstr);
else {
if (!axis_homed[axis])
lcd_printPGM(PSTR("?"));
else {
if (!axis_known_position[axis])
lcd_printPGM(PSTR(" "));
else
lcd_printPGM(pstr);
}
}
}
static void lcd_implementation_status_screen() {
u8g.setColorIndex(1); // black on white
......@@ -458,34 +473,20 @@ static void lcd_implementation_status_screen() {
u8g.setColorIndex(0); // white on black
u8g.setPrintPos(2, XYZ_BASELINE);
lcd_print(TEST(axis_known_position, X_AXIS) || !TEST(axis_was_homed, X_AXIS) ? 'X' : '?');
u8g.drawPixel(8, XYZ_BASELINE - 5);
u8g.drawPixel(8, XYZ_BASELINE - 3);
_draw_axis_label(X_AXIS, PSTR(MSG_X), blink);
u8g.setPrintPos(10, XYZ_BASELINE);
if (TEST(axis_was_homed, X_AXIS))
lcd_print(ftostr31ns(current_position[X_AXIS]));
else
lcd_printPGM(PSTR("---"));
lcd_print(ftostr4sign(current_position[X_AXIS]));
u8g.setPrintPos(43, XYZ_BASELINE);
lcd_print(TEST(axis_known_position, Y_AXIS) || !TEST(axis_was_homed, Y_AXIS) ? 'Y' : '?');
u8g.drawPixel(49, XYZ_BASELINE - 5);
u8g.drawPixel(49, XYZ_BASELINE - 3);
_draw_axis_label(Y_AXIS, PSTR(MSG_Y), blink);
u8g.setPrintPos(51, XYZ_BASELINE);
if (TEST(axis_was_homed, Y_AXIS))
lcd_print(ftostr31ns(current_position[Y_AXIS]));
else
lcd_printPGM(PSTR("---"));
lcd_print(ftostr4sign(current_position[Y_AXIS]));
u8g.setPrintPos(83, XYZ_BASELINE);
lcd_print(TEST(axis_known_position, Z_AXIS) || !TEST(axis_was_homed, Z_AXIS) ? 'Z' : '?');
u8g.drawPixel(89, XYZ_BASELINE - 5);
u8g.drawPixel(89, XYZ_BASELINE - 3);
_draw_axis_label(Z_AXIS, PSTR(MSG_Z), blink);
u8g.setPrintPos(91, XYZ_BASELINE);
if (TEST(axis_was_homed, Z_AXIS))
lcd_print(ftostr32sp(current_position[Z_AXIS]));
else
lcd_printPGM(PSTR("---.--"));
lcd_print(ftostr32sp(current_position[Z_AXIS] + 0.00001));
u8g.setColorIndex(1); // black on white
// Feedrate
......
......@@ -2034,6 +2034,17 @@ int lcd_strlen_P(const char* s) {
return j;
}
bool lcd_blink() {
static uint8_t blink = 0;
static millis_t next_blink_ms = 0;
millis_t ms = millis();
if (ELAPSED(ms, next_blink_ms)) {
blink ^= 0xFF;
next_blink_ms = ms + 1000 - LCD_UPDATE_INTERVAL / 2;
}
return blink != 0;
}
/**
* Update the LCD, read encoder buttons, etc.
* - Read button states
......@@ -2096,7 +2107,7 @@ void lcd_update() {
#if ENABLED(REPRAPWORLD_KEYPAD)
#if ENABLED(DELTA) || ENABLED(SCARA)
#if MECH(DELTA) || MECH(SCARA)
#define _KEYPAD_MOVE_ALLOWED (axis_homed[X_AXIS] && axis_homed[Y_AXIS] && axis_homed[Z_AXIS])
#else
#define _KEYPAD_MOVE_ALLOWED true
......
......@@ -575,6 +575,21 @@ unsigned lcd_print(char c) { return charset_mapper(c); }
}
#endif // SHOW_BOOTSCREEN
FORCE_INLINE void _draw_axis_label(AxisEnum axis, const char *pstr, bool blink) {
if (blink)
lcd_printPGM(pstr);
else {
if (!axis_homed[axis])
lcd_printPGM(PSTR("?"));
else {
if (!axis_known_position[axis])
lcd_printPGM(PSTR(" "));
else
lcd_printPGM(pstr);
}
}
}
/*
Possible status screens:
16x2 |000/000 B000/000|
......@@ -668,6 +683,8 @@ static void lcd_implementation_status_screen() {
#if LCD_HEIGHT > 2
bool blink = lcd_blink();
#if LCD_WIDTH < 20
#if ENABLED(SDSUPPORT)
......@@ -684,12 +701,6 @@ static void lcd_implementation_status_screen() {
lcd.setCursor(0, 1);
//
// Print XYZ Coordinates
// If the axis was not homed, show "---"
// If the position is untrusted, show "?"
//
#if HOTENDS > 1 && TEMP_SENSOR_BED != 0
// If we both have a 2nd hotend and a heated bed,
......@@ -698,29 +709,25 @@ static void lcd_implementation_status_screen() {
LCD_TEMP(degBed(), degTargetBed(), LCD_STR_BEDTEMP[0]);
#else
// Before homing the axis letters are blinking 'X' <-> '?'.
// When axis is homed but axis_known_position is false the axis letters are blinking 'X' <-> ' '.
// When everything is ok you see a constant 'X'.
lcd.print(TEST(axis_known_position, X_AXIS) || !TEST(axis_was_homed, X_AXIS) ? 'X' : '?');
if (TEST(axis_was_homed, X_AXIS))
_draw_axis_label(X_AXIS, PSTR(MSG_X), blink);
lcd.print(ftostr4sign(current_position[X_AXIS]));
else
lcd_printPGM(PSTR(" ---"));
lcd_printPGM(TEST(axis_known_position, Y_AXIS) || !TEST(axis_was_homed, Y_AXIS) ? PSTR(" Y") : PSTR(" ?"));
if (TEST(axis_was_homed, Y_AXIS))
lcd_printPGM(PSTR(" "));
_draw_axis_label(Y_AXIS, PSTR(MSG_Y), blink);
lcd.print(ftostr4sign(current_position[Y_AXIS]));
else
lcd_printPGM(PSTR(" ---"));
#endif // HOTENDS > 1 || TEMP_SENSOR_BED != 0
#endif // LCD_WIDTH >= 20
lcd.setCursor(LCD_WIDTH - 8, 1);
lcd_printPGM(TEST(axis_known_position, Z_AXIS) || !TEST(axis_was_homed, Z_AXIS) ? PSTR("Z ") : PSTR("? "));
if (TEST(axis_was_homed, Z_AXIS))
_draw_axis_label(Z_AXIS, PSTR(MSG_Z), blink);
lcd.print(ftostr32sp(current_position[Z_AXIS] + 0.00001));
else
lcd_printPGM(PSTR("---.--"));
#endif // LCD_HEIGHT > 2
......@@ -807,12 +814,12 @@ static void lcd_implementation_status_screen() {
//Display both Status message line and Filament display on the last line
#if HAS(LCD_FILAMENT_SENSOR) || HAS(LCD_POWER_SENSOR)
if (millis() >= previous_lcd_status_ms + 5000) {
if (millis() >= previous_lcd_status_ms + 5000UL) {
lcd_print(lcd_status_message);
}
#if HAS(LCD_POWER_SENSOR)
#if HAS(LCD_FILAMENT_SENSOR)
else if (millis() < message_millis + 10000)
else if (millis() < message_millis + 10000UL)
#else
else
#endif
......@@ -829,7 +836,7 @@ static void lcd_implementation_status_screen() {
lcd_printPGM(PSTR("Dia "));
lcd.print(ftostr12ns(filament_width_meas));
lcd_printPGM(PSTR(" V"));
lcd.print(itostr3(100.0*volumetric_multiplier[FILAMENT_SENSOR_EXTRUDER_NUM]));
lcd.print(itostr3(100.0 * volumetric_multiplier[FILAMENT_SENSOR_EXTRUDER_NUM]));
lcd.print('%');
return;
}
......@@ -900,17 +907,20 @@ static void lcd_implementation_drawmenu_setting_edit_generic_P(bool sel, uint8_t
#define lcd_implementation_drawmenu_setting_edit_callback_long5(sel, row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, '>', ftostr5(*(data)))
#define lcd_implementation_drawmenu_setting_edit_callback_bool(sel, row, pstr, pstr2, data, callback) lcd_implementation_drawmenu_setting_edit_generic_P(sel, row, pstr, '>', (*(data))?PSTR(MSG_ON):PSTR(MSG_OFF))
void lcd_implementation_drawedit(const char* pstr, char* value) {
void lcd_implementation_drawedit(const char* pstr, const char* value = NULL) {
lcd.setCursor(1, 1);
lcd_printPGM(pstr);
if (value != NULL) {
lcd.print(':');
lcd.setCursor(LCD_WIDTH - lcd_strlen(value), 1);
lcd_print(value);
}
}
#if ENABLED(SDSUPPORT)
static void lcd_implementation_drawmenu_sd(bool sel, uint8_t row, const char* pstr, const char* longFilename, uint8_t concat, char post_char) {
UNUSED(pstr);
char c;
uint8_t n = LCD_WIDTH - concat;
lcd.setCursor(0, row);
......
......@@ -48,14 +48,9 @@
#define ENABLED defined
#define DISABLED !defined
#define PIN_EXISTS(PN) (defined(PN##_PIN) && PN##_PIN >= 0)
#define HAS(FE) (HAS_##FE)
#define HASNT(FE) (!(HAS_##FE))
#define PENDING(NOW,SOON) ((long)(NOW-(SOON))<0)
#define ELAPSED(NOW,SOON) (!PENDING(NOW,SOON))
// Macros to contrain values
#define NUMERIC(a) ((a) >= '0' && '9' >= (a))
#define NUMERIC_SIGNED(a) (NUMERIC(a) || (a) == '-')
......@@ -73,4 +68,12 @@
#define STRINGIFY_(n) #n
#define STRINGIFY(n) STRINGIFY_(n)
// Macro for varie
#define PIN_EXISTS(PN) (defined(PN##_PIN) && PN##_PIN >= 0)
#define PENDING(NOW,SOON) ((long)(NOW-(SOON))<0)
#define ELAPSED(NOW,SOON) (!PENDING(NOW,SOON))
#define NOOP do{}while(0)
#endif //__MACROS_H
......@@ -532,12 +532,13 @@ float junction_deviation = 0.1;
// The target position of the tool in absolute steps
// Calculate target position in absolute steps
//this should be done after the wait, because otherwise a M92 code within the gcode disrupts this calculation somehow
int32_t target[NUM_AXIS];
target[X_AXIS] = lround(x * axis_steps_per_unit[X_AXIS]);
target[Y_AXIS] = lround(y * axis_steps_per_unit[Y_AXIS]);
target[Z_AXIS] = lround(z * axis_steps_per_unit[Z_AXIS]);
target[E_AXIS] = lround(e * axis_steps_per_unit[E_AXIS + extruder]);
// this should be done after the wait, because otherwise a M92 code within the gcode disrupts this calculation somehow
int32_t target[NUM_AXIS] = {
lround(x * axis_steps_per_unit[X_AXIS]),
lround(y * axis_steps_per_unit[Y_AXIS]),
lround(z * axis_steps_per_unit[Z_AXIS]),
lround(e * axis_steps_per_unit[E_AXIS + extruder])
};
// If changing extruder have to recalculate current position based on
// the steps-per-mm value for the new extruder.
......
......@@ -305,7 +305,7 @@ void checkHitEndstops() {
card.sdprinting = false;
card.closeFile();
#endif
for (int i = 0; i < 3; i++) CBI(axis_known_position, i); // not homed anymore
for (int i = 0; i < 3; i++) axis_known_position[i] = true; // not homed anymore
quickStop(); // kill the planner buffer
Stop(); // restart by M999
}
......@@ -656,12 +656,11 @@ ISR(TIMER1_COMPA_vect) {
trapezoid_generator_reset();
// Initialize Bresenham counters to 1/2 the ceiling
long new_count = -(current_block->step_event_count >> 1);
counter_X = counter_Y = counter_Z = counter_E = new_count;
counter_X = counter_Y = counter_Z = counter_E = -(current_block->step_event_count >> 1);
#if ENABLED(COLOR_MIXING_EXTRUDER)
for (uint8_t i = 0; i < DRIVER_EXTRUDERS; i++)
counter_m[i] = new_count;
counter_m[i] = -(current_block->step_event_count >> 1);
#endif
step_events_completed = 0;
......
......@@ -188,7 +188,7 @@
#define E5_ENABLE_READ READ(E5_ENABLE_PIN)
#if ENABLED(COLOR_MIXING_EXTRUDER)
#define E_STEP_WRITE(v) ; /* not used for mixing extruders! */
#define E_STEP_WRITE(v) NOOP /* not used for mixing extruders! */
#if DRIVER_EXTRUDERS > 5
#define En_STEP_WRITE(n,v) { switch (n) { case 0: E0_STEP_WRITE(v); break; case 1: E1_STEP_WRITE(v); break; case 2: E2_STEP_WRITE(v); break; case 3: E3_STEP_WRITE(v); break; case 4: E4_STEP_WRITE(v); break; case 5: E5_STEP_WRITE(v); } }
#define NORM_E_DIR() { E0_DIR_WRITE(!INVERT_E0_DIR); E1_DIR_WRITE(!INVERT_E1_DIR); E2_DIR_WRITE(!INVERT_E2_DIR); E3_DIR_WRITE(!INVERT_E3_DIR); E4_DIR_WRITE(!INVERT_E4_DIR); E5_DIR_WRITE(!INVERT_E5_DIR); }
......@@ -254,7 +254,7 @@
#define disable_x() do { X_ENABLE_WRITE(!X_ENABLE_ON); X2_ENABLE_WRITE(!X_ENABLE_ON); CBI(axis_known_position, X_AXIS); } while (0)
#elif HAS(X_ENABLE)
#define enable_x() X_ENABLE_WRITE( X_ENABLE_ON)
#define disable_x() { X_ENABLE_WRITE(!X_ENABLE_ON); CBI(axis_known_position, X_AXIS); }
#define disable_x() { X_ENABLE_WRITE(!X_ENABLE_ON); axis_known_position[X_AXIS] = false; }
#else
#define enable_x() ;
#define disable_x() ;
......@@ -266,7 +266,7 @@
#define disable_y() { Y_ENABLE_WRITE(!Y_ENABLE_ON); Y2_ENABLE_WRITE(!Y_ENABLE_ON); CBI(axis_known_position, Y_AXIS); }
#else
#define enable_y() Y_ENABLE_WRITE( Y_ENABLE_ON)
#define disable_y() { Y_ENABLE_WRITE(!Y_ENABLE_ON); CBI(axis_known_position, Y_AXIS); }
#define disable_y() { Y_ENABLE_WRITE(!Y_ENABLE_ON); axis_known_position[Y_AXIS] = false; }
#endif
#else
#define enable_y() ;
......@@ -276,10 +276,10 @@
#if HAS(Z_ENABLE)
#if ENABLED(Z_DUAL_STEPPER_DRIVERS)
#define enable_z() { Z_ENABLE_WRITE( Z_ENABLE_ON); Z2_ENABLE_WRITE(Z_ENABLE_ON); }
#define disable_z() { Z_ENABLE_WRITE(!Z_ENABLE_ON); Z2_ENABLE_WRITE(!Z_ENABLE_ON); CBI(axis_known_position, Z_AXIS); }
#define disable_z() { Z_ENABLE_WRITE(!Z_ENABLE_ON); Z2_ENABLE_WRITE(!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; }
#else
#define enable_z() Z_ENABLE_WRITE( Z_ENABLE_ON)
#define disable_z() { Z_ENABLE_WRITE(!Z_ENABLE_ON); CBI(axis_known_position, Z_AXIS); }
#define disable_z() { Z_ENABLE_WRITE(!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; }
#endif
#else
#define enable_z() ;
......@@ -305,16 +305,16 @@
#define disable_e0() { E0_ENABLE_WRITE(!E_ENABLE_ON); E1_ENABLE_WRITE(!E_ENABLE_ON); }
#endif
#define enable_e1() ;
#define disable_e1() ;
#define enable_e2() ;
#define disable_e2() ;
#define enable_e3() ;
#define disable_e3() ;
#define enable_e4() ;
#define disable_e4() ;
#define enable_e5() ;
#define disable_e5() ;
#define enable_e1() NOOP
#define disable_e1() NOOP
#define enable_e2() NOOP
#define disable_e2() NOOP
#define enable_e3() NOOP
#define disable_e3() NOOP
#define enable_e4() NOOP
#define disable_e4() NOOP
#define enable_e5() NOOP
#define disable_e5() NOOP
#else // !COLOR_MIXING_EXTRUDER
......@@ -322,48 +322,48 @@
#define enable_e0() E0_ENABLE_WRITE( E_ENABLE_ON)
#define disable_e0() E0_ENABLE_WRITE(!E_ENABLE_ON)
#else
#define enable_e0() /* nothing */
#define disable_e0() /* nothing */
#define enable_e0() NOOP
#define disable_e0() NOOP
#endif
#if (DRIVER_EXTRUDERS > 1) && HAS(E1_ENABLE)
#define enable_e1() E1_ENABLE_WRITE( E_ENABLE_ON)
#define disable_e1() E1_ENABLE_WRITE(!E_ENABLE_ON)
#else
#define enable_e1() /* nothing */
#define disable_e1() /* nothing */
#define enable_e1() NOOP
#define disable_e1() NOOP
#endif
#if (DRIVER_EXTRUDERS > 2) && HAS(E2_ENABLE)
#define enable_e2() E2_ENABLE_WRITE( E_ENABLE_ON)
#define disable_e2() E2_ENABLE_WRITE(!E_ENABLE_ON)
#else
#define enable_e2() /* nothing */
#define disable_e2() /* nothing */
#define enable_e2() NOOP
#define disable_e2() NOOP
#endif
#if (DRIVER_EXTRUDERS > 3) && HAS(E3_ENABLE)
#define enable_e3() E3_ENABLE_WRITE( E_ENABLE_ON)
#define disable_e3() E3_ENABLE_WRITE(!E_ENABLE_ON)
#else
#define enable_e3() /* nothing */
#define disable_e3() /* nothing */
#define enable_e3() NOOP
#define disable_e3() NOOP
#endif
#if (DRIVER_EXTRUDERS > 4) && HAS(E4_ENABLE)
#define enable_e4() E4_ENABLE_WRITE( E_ENABLE_ON)
#define disable_e4() E4_ENABLE_WRITE(!E_ENABLE_ON)
#else
#define enable_e4() /* nothing */
#define disable_e4() /* nothing */
#define enable_e4() NOOP
#define disable_e4() NOOP
#endif
#if (DRIVER_EXTRUDERS > 5) && HAS(E5_ENABLE)
#define enable_e5() E5_ENABLE_WRITE( E_ENABLE_ON)
#define disable_e5() E5_ENABLE_WRITE(!E_ENABLE_ON)
#else
#define enable_e5() /* nothing */
#define disable_e5() /* nothing */
#define enable_e5() NOOP
#define disable_e5() NOOP
#endif
#endif
......
......@@ -612,29 +612,23 @@
char* valuetemp;
memset(buffer, 0, sizeof(buffer));
strcat(buffer, TEST(axis_known_position, X_AXIS) || !TEST(axis_was_homed, X_AXIS) ? "X" : "?");
if (TEST(axis_was_homed, X_AXIS)) {
strcat(buffer, (axis_known_position[X_AXIS] ? "X" : "?"));
if (axis_homed[X_AXIS]) {
valuetemp = ftostr4sign(current_position[X_AXIS]);
strcat(buffer, valuetemp);
}
else
strcat(buffer, "---");
strcat(buffer, TEST(axis_known_position, Y_AXIS) || !TEST(axis_was_homed, Y_AXIS) ? PSTR(" Y") : PSTR(" ?"));
if (TEST(axis_was_homed, Y_AXIS)) {
strcat(buffer, (axis_known_position[Y_AXIS] ? " Y" : " ?"));
if (axis_homed[Y_AXIS]) {
valuetemp = ftostr4sign(current_position[Y_AXIS]);
strcat(buffer, valuetemp);
}
else
strcat(buffer, "---");
strcat(buffer, TEST(axis_known_position, Z_AXIS) || !TEST(axis_was_homed, Z_AXIS) ? PSTR(" Z ") : PSTR("? "));
if (TEST(axis_was_homed, Z_AXIS)) {
strcat(buffer, (axis_known_position[Z_AXIS] ? " Z " : " ? "));
if (axis_homed[Z_AXIS]) {
valuetemp = ftostr32sp(current_position[Z_AXIS] + 0.00001);
strcat(buffer, valuetemp);
}
else
strcat(buffer, "---");
LedCoord1.setText(buffer);
LedCoord6.setText(buffer);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment