Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Comprehensive BLTouch implementation #13841

Closed
wants to merge 31 commits into from
Closed
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
08e2a47
BLTouch recode 20190428
FanDjango Apr 28, 2019
8226fa9
Fix indentation
FanDjango Apr 28, 2019
1b5e111
White space remove
FanDjango Apr 28, 2019
9cedd30
Update G34_M422.cpp
FanDjango Apr 28, 2019
5b0ac05
Merge branch 'bugfix-2.0.x' into bugfix-2.0-x-SPECIAL-BLTOUCH-RELEASE
FanDjango Apr 29, 2019
fac5e30
Typos
FanDjango Apr 29, 2019
c75639c
BLTouch recode stage 2
FanDjango Apr 29, 2019
aeb266d
Exclude RESET command from delay termination
FanDjango Apr 29, 2019
29c3d40
More refactoring
FanDjango Apr 29, 2019
305928b
Small changes
FanDjango Apr 30, 2019
08c37ce
Remove command delay pre-exit
FanDjango Apr 30, 2019
09f6983
Revert "Remove command delay pre-exit"
FanDjango Apr 30, 2019
f99c7ee
Fixed, deleted one line to many
FanDjango Apr 30, 2019
a6692e2
Merge branch 'bugfix-2.0.x' into bugfix-2.0-x-SPECIAL-BLTOUCH-RELEASE
FanDjango May 1, 2019
e68abf4
Update Configuration.h
FanDjango May 1, 2019
2220afd
Merge branch 'bugfix-2.0.x' into bugfix-2.0-x-SPECIAL-BLTOUCH-RELEASE
FanDjango May 2, 2019
e377dcf
Stage 3
FanDjango May 2, 2019
adf902c
Compile on DUE fails : IsRunning TODO
FanDjango May 2, 2019
8505f9f
Another compile fail on DUE - TODO someday
FanDjango May 2, 2019
7309e87
Revert "Another compile fail on DUE - TODO someday"
FanDjango May 3, 2019
57d3b2f
Revert "Compile on DUE fails : IsRunning TODO"
FanDjango May 3, 2019
eb1216f
Revert "Stage 3"
FanDjango May 3, 2019
0d4531c
Add BLTouch::status()
FanDjango May 3, 2019
2deb61d
Start a section for BLTouch Sanity Check
FanDjango May 3, 2019
c3a2cbc
Add SW Mode to M119
FanDjango May 3, 2019
8321995
Update a comment
FanDjango May 3, 2019
1103a79
Update SanityCheck.h
FanDjango May 3, 2019
ed93c56
Merge remote-tracking branch 'upstream/bugfix-2.0.x' into bugfix-2.0-…
FanDjango May 3, 2019
f9f5676
fix Typo
FanDjango May 3, 2019
9f0573e
Merge branch 'bugfix-2.0.x' into bugfix-2.0-x-SPECIAL-BLTOUCH-RELEASE
FanDjango May 4, 2019
3cf4209
Merge branch 'bugfix-2.0.x' into bugfix-2.0-x-SPECIAL-BLTOUCH-RELEASE
FanDjango May 5, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 37 additions & 7 deletions Marlin/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -825,17 +825,47 @@
*/
//#define BLTOUCH
#if ENABLED(BLTOUCH)
//#define BLTOUCH_DELAY 375 // (ms) Enable and increase if needed

/**
* BLTouch V3.0 and newer smart series
* For genuine BLTouch 3.0 sensors. Clones may be confused by 3.0 command angles. YMMV.
* If the pin trigger is not detected, first try swapping the black and white wires then toggle this.
* For all BLTouch probes and clones:
*/
//#define BLTOUCH_DEBUG_MSGS // Produce some debugging messages when commands are issued to the probe
//#define BLTOUCH_DELAY 375 // (ms) Allow the servo signal to settle for this long before the next command
// Note: This is the sane default. Some setups will tolerate lower values.

/**
* For BLTouch V2.0 and newer probes which support SW mode. Some clones do too.
* Set the probe into SW mode, producing a longer pulse when triggered, useful when there
* is noise or high capacitance on the signal pin.
* If your probe works fine without this, don't turn it on, as it slows down probing
* Note: Performing a STOW and then setting this mode in the LCD BLTouch configuration menu
* manually will alloy you to check the wiring with a M119 command. You don't need to enable
* this in order to be able to do that.
*/
//#define BLTOUCH_FORCE_SW_MODE

/**
* For BLTouch V3.0 and newer probes:
* If you want the new functions of the BLTouch V3 or you need 5V mode (see below), enable this.
* This adds the special V3 commands (5V and OD modes) to the LCD configuration menu for BLTouch
*/
//#define BLTOUCH_V3
#if ENABLED(BLTOUCH_V3)
#if ENABLED(BLTOUCH_V3)
/**
* These probes default to OPEN DRAIN mode. All other probes are in 5V mode per default.
* If you have a BLTouch V3.0 or newer and explicitely want 5V mode, use this define - this
* makes it more compatible with previous probe versions.
* Warning: Make sure your controller boards input pin is 5V tolerant.
*/
//#define BLTOUCH_FORCE_5V_MODE
//#define BLTOUCH_FORCE_OPEN_DRAIN_MODE
/**
* Advanced users who fervently believe in the reliability of their BLTouch probes can
* activate the HIGH SPEED mode for their unit. This will reduce the timing so far that
* DEPLOY and STOW failures are only captured on the NEXT such command to be issued.
* The result is faster probing but much less surety of catching and identifying errors.
* NOT RECOMMENDED for novice users and in unstable environments. As homing and probing are
* not done so often, the speed gain is nice but not really life changing.
*/
//#define BLTOUCH_HS_MODE
#endif
#endif

Expand Down
161 changes: 124 additions & 37 deletions Marlin/src/feature/bltouch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,8 @@ void stop();
#define DEBUG_OUT ENABLED(DEBUG_LEVELING_FEATURE)
#include "../core/debug_out.h"

void BLTouch::command(const BLTCommand cmd) {
//SERIAL_ECHOLNPAIR("BLTouch Command :", cmd);
MOVE_SERVO(Z_PROBE_SERVO_NR, cmd);
safe_delay(BLTOUCH_DELAY);
}

void BLTouch::init() {
reset(); // Clear all BLTouch error conditions
stow();
}

bool BLTouch::triggered() {
// Used in the main loop to check the pin state when probing and internally here
return (
#if ENABLED(Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN)
READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING
Expand All @@ -56,41 +46,138 @@ bool BLTouch::triggered() {
);
}

bool BLTouch::set_deployed(const bool in_deploy) {
if (in_deploy && triggered()) { // If BLTouch says it's triggered
reset(); // try to reset it.
_deploy(); _stow(); // Deploy and stow to clear the "triggered" condition.
safe_delay(1500); // Wait for internal self-test to complete.
// (Measured completion time was 0.65 seconds
// after reset, deploy, and stow sequence)
if (triggered()) { // If it still claims to be triggered...
SERIAL_ERROR_MSG(MSG_STOP_BLTOUCH);
stop(); // punt!
return true;
}
void BLTouch::init() {
// This is called by marlin.cpp on initialization
// SET_5V_MODE (if enabled). OD_MODE is the default on power on.
// This mode will stay active until manual SET_OD_MODE or power cycle
#if ENABLED(BLTOUCH_FORCE_5V_MODE)
_set_5V_mode(); // Set 5V mode if explicitely demanded (V3 upwards)
#endif
clear();
// There really should be no alarm outstanding now, and no triggered condition. But if there is,
// there is no need to worry people here on init right at the start of the printer.
}

void BLTouch::clear() {
_reset(); // RESET or RESET_SW will clear an alarm condition but...
// ...it will not clear a triggered condition in SW mode when the pin is currently up
// ANTClabs <-- CODE ERROR
_stow(); // STOW will pull up the pin and clear any triggered condition unless it fails, don't care
_deploy(); // DEPLOY to test the probe. Could fail, don't care
_stow(); // STOW to be ready for meaningful work. Could fail, don't care
}

bool BLTouch::command(const BLTCommand cmd, millis_t ms) {
#if ENABLED(BLTOUCH_DEBUG_MSGS)
SERIAL_ECHOLNPAIR("BLTouch Command :", cmd);
#endif
MOVE_SERVO(Z_PROBE_SERVO_NR, cmd);
// If BLTOUCH_DELAY is higher than the desired ms delay, it will override
if (BLTOUCH_DELAY > ms) {
ms = BLTOUCH_DELAY;
}
// Don't wait longer than necessary if an ALARM pops up. Check trigger
// in increments of 50ms to catch the ALARM right away.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pulse width of a trigger is 10ms. There is a good chance this will be picked up by this at some point. Should have a flag for triggered seen and only fault out of true twice in a row. Also, this wont truly wait safe delay, It may be off by up to 49ms. Could do while(ms > 0) then safe_delay MIN(ms, 50));

Copy link
Author

@ghost ghost Apr 30, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, this wont truly wait safe delay, It may be off by up to 49ms. Could do while(ms > 0) then safe_delay MIN(ms, 50));

safe_delay():

void safe_delay(millis_t ms) {
  while (ms > 50) {
    ms -= 50;
    delay(50);
    thermalManager.manage_heater();
  }
  delay(ms);
  thermalManager.manage_heater(); // This keeps us safe if too many small safe_delay() calls are made
}

Why might this be off by 49ms? It does a possible rest value outside the loop at the end?
Apart from the timing overhead of thermalManger.manage_heater() it looks reasonably precise.

Copy link
Author

@ghost ghost Apr 30, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a good chance this will be picked up by this at some point.

I though that unless something is very wrong, there should never be a trigger while in this loop. If this is a wait after a DEPLOY, movement only begins after the wait is over. Similar logic applies to the other commands.

Should have a flag for triggered seen and only fault out of true twice in a row.

But that is a really good idea to not get out of the loop when there is noise.

And you are right: In no case do we want to get into a situation where we might issue the next command before the wait for the previous command is over.

I think it would be best to scrap this exiting of the loop altogether. I kind of though it would speed up things - but we are talking about reducing (for example) a 750ms STOW wait to 350ms, who cares actually. How often do we probe, anyway.

So I will remove the two lines and let's let the wait do its thing without any pre-exit.

What do think of putting thermalManager.manage_heater(); in there and not calling safe_delay but just delay? It would mean an include for temperature.h at the top though. In the end I was against it, but didn't evaluate code-bytes against the two versions.

Copy link
Author

@ghost ghost Apr 30, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could do while(ms > 0) then safe_delay MIN(ms, 50));

Yes very nice idea for the original safe_delay by the way, but how does the code bytes overhead of MIN compare to just doing the rest after the end of the loop?

Original:

void safe_delay(millis_t ms) {
  while (ms > 50) {
    ms -= 50;
    delay(50);
    thermalManager.manage_heater();
  }
  delay(ms);
  thermalManager.manage_heater(); // This keeps us safe if too many small safe_delay() calls are made
}

New idea:

void safe_delay(millis_t ms) {
  while (ms > 50) {
    ms -= 50;
    delay MIN(ms, 50))
    thermalManager.manage_heater();
  }
}

Looks shorter but how expensive is MIN (its a a couple of branches and an immediate compare, I think) vs. two call instructions. Could be smaller, if you want I will compile and compare the OBJ code (8 bit and 32 bit, of course).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 'new idea' will break things... If safe_delay() is called with a small amount of time... say 25ms, no delay will be performed.

Copy link
Member

@Roxy-3D Roxy-3D May 1, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah! That code is super easy to KNOW the right thing is going to happen. I much prefer that form. And incidentally... That is more 'optimum' too. That will generate less machine language code than what is there right now.

Copy link
Author

@ghost ghost May 1, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have checked:

The MIN is expensive.

The "new idea" looks better in the c code. As I feared: It is longer on AVR machine code. It is slightly longer on 32 bit code. The original code knew what he was doing.

Do we care about 10-20 bytes of machine code in this specific case? In general, we do.

Copy link
Member

@Roxy-3D Roxy-3D May 1, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

10 or 20 bytes isn't a big deal to make sure the problem is fixed... With regard to MIN() being expensive... In this case we know the data types going into the macro. If we side step the MIN() macro and just use a ternary operator, I would think this ends up as small as possible. The big problem is the type millis is a 4 byte long. And those comparisons and arithmetic are not 'natural' on the 8-bit AVR's.

void safe_delay(millis_t ms) {
  while (ms > 0) {
    delay( ms<50? ms : 50);
    ms -= 50;
    thermalManager.manage_heater();
  }
}

Copy link
Author

@ghost ghost May 1, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup. The original coder knew what he was doing. ms<50? ms : 50 in machine code is loads for the ms var, multiple compares and 2 branches. The original one is shorter in machine code, believe me. But less shorter on 32 bit machines. AVR - it's hell.

If I were a CPU I would go berserk anyway, first the guy is asking while (ms > 50) god knows how many times, and then he wants to know ms < 50 that many times. Bonkers, right?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to make sure the problem is fixed

But there is actually no problem

// Instead of using safe_delay in the following loop, we could use delay
// and do the calling of the temperature-manager ourself. See safe_delay() for
// details. TODO
while (ms > 50) {
ms -= 50;
safe_delay(50);
if (cmd == BLTOUCH_RESET) continue;
if (triggered()) return true;
}
safe_delay(ms);
return triggered();
}

#if ENABLED(BLTOUCH_V3)
#if EITHER(BLTOUCH_FORCE_5V_MODE, ENDSTOPPULLUPS) \
|| ALL(Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN, ENDSTOPPULLUP_ZMIN) \
|| (USES_Z_MIN_PROBE_ENDSTOP && ENABLED(ENDSTOPPULLUP_ZMIN_PROBE))
set_5V_mode(); // Assume 5V DC logic level if endstop pullup resistors are enabled
#elif true || ENABLED(BLTOUCH_FORCE_OPEN_DRAIN_MODE)
set_OD_mode();
bool BLTouch::deploy_wrapper() {
// Do a DEPLOY
#if ENABLED(BLTOUCH_DEBUG_MSGS)
SERIAL_ECHOLN("BLTouch DEPLOY requested");
#endif

// Attempt to DEPLOY, wait for DEPLOY_DELAY or ALARM
if (_deploy_query_alarm()) {
// The deploy might have failed or the probe is already triggered (nozzle too low?)
#if ENABLED(BLTOUCH_DEBUG_MSGS)
SERIAL_ECHOLN("BLTouch ALARM or TRIGGER after DEPLOY, recovering");
#endif

clear(); // Get the probe into start condition

// Last attempt to DEPLOY
if (_deploy_query_alarm()) {
// The deploy might have failed or the probe is actually triggered (nozzle too low?) again
#if ENABLED(BLTOUCH_DEBUG_MSGS)
SERIAL_ECHOLN("BLTouch ALARM or TRIGGER after DEPLOY, recovery failed");
#endif

SERIAL_ERROR_MSG(MSG_STOP_BLTOUCH); // Tell the user something is wrong, needs action
stop(); // but i'ts not too bad, no need to kill, allow restart

return true; // Tell our caller we goofed in case he cares to know
}
}

// The BLTouch V3 (and V2) and some clones can be used in "SWITCH" mode. When triggered,
// instead of a 10ms pulse, there is an indefinetly long trigger condition, until
// reset by the STOW as soon as this "very very long" pulse is registered. Might help in cases
// where the trigger pulse is difficult to register (noise, caps on the signal)
// Entering this mode manually also enables M119 display of the probe pin state.
#if ENABLED(BLTOUCH_FORCE_SW_MODE)
_set_SW_mode(); // If explicitely demanded, RESET into SW mode
#endif

if (in_deploy) {
_deploy();
#if ENABLED(BLTOUCH_V3)
set_SW_mode();
// Now the probe is ready to issue a 10ms pulse (or longer, if in SW mode) when the pin goes up.
// The trigger STOW (see motion.cpp for example) will pull up the probes pin as soon as the pulse
// is registered.

if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("bltouch.deploy_wrapper()");

return false; // report success to caller
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be reversed. True for command successful, and false for command failed. Thats the typical convention.

Copy link
Author

@ghost ghost Apr 30, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be my preference as well. It would be easy to inverse the logic at all the very few occurences where these wrappers are called. Note that I have seen a few other places where "false" is "success" in Marlin, so I believe that the original coder of bltouch probably thought that he should adhere to it. I just stuck to that logic. Look at the original bltouch.cpp, that's where I took it from.

The callers typically look like this:

if (triggered() & wrapper(...)) -> error exit
... success code...

So it needs a true to error out.

Saves quite some machine instructions (8-bit code size) was probably the reasoning.

Oherwise it would have been:

if (triggered() & !wrapper(...)) -> error exit
... success code...

One instruction more at least.

Other constructs using if then else are also possible but use even more instructions in otherwise straight line code.

Sooner or later one should identify these places and gradually turn the logic around.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True for command successful, and false for command failed. Thats the typical convention.

In fact, a very common convention is zero for no error, or non-zero for an error code.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't write the original, @thinkyhead
Seen so many places in Marlin where this is "the wrong way around" - correcting them all would give AVR maybe 100 bytes more program code. 32 bit who cares, but AVR?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example, one out of many (probe.cpp):
grafik
It's all over the place. So lecture the original author. But like I said, he liked coding it that way...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's another one in motion.cpp:
grafik
I just wanted to conform to the prevalent coding style so as not to break anything.

}

bool BLTouch::stow_wrapper() {
// Do a STOW
#if ENABLED(BLTOUCH_DEBUG_MSGS)
SERIAL_ECHOLN("BLTouch STOW requested");
#endif

// A STOW will clear a triggered condition in the probe (10ms pulse or the "very very long" pulse
// in SW mode).
// At the moment that we come in here, we might (pulse) or will (SW mode) see the trigger on the pin.
// So even though we know a STOW will be ignored if an ALARM condition is active, we will STOW.
// Note: If the probe is deployed AND in an ALARM condition, this STOW will not pull up the pin
// and the ALARM condition will still be there. --> ANTClabs should change this behaviour maybe

// Attempt to STOW, wait for STOW_DELAY or ALARM
if (_stow_query_alarm()) {
// The stow might have failed
#if ENABLED(BLTOUCH_DEBUG_MSGS)
SERIAL_ECHOLN("BLTouch ALARM or TRIGGER after STOW, recovering");
#endif

_reset(); // This RESET will then also pull up the pin. If it doesn't
// work and the pin is still down, there will no longer be
// an ALARM condition though.
// But one more STOW will catch that
// Last attempt to STOW
if (_stow_query_alarm()) { // so if there is now STILL an ALARM condition:
#if ENABLED(BLTOUCH_DEBUG_MSGS)
SERIAL_ECHOLN("BLTouch ALARM or TRIGGER after STOW, recovery failed");
#endif

SERIAL_ERROR_MSG(MSG_STOP_BLTOUCH); // Tell the user something is wrong, needs action
stop(); // but it's not too bad, no need to kill, allow restart

return true; // Tell our caller we goofed in case he cares to know
}
}
else _stow();

if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("bltouch.set_deployed(", in_deploy, ")");
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("bltouch.stow_wrapper()");

return false;
return false; // report success to caller
}

#endif // BLTOUCH
74 changes: 54 additions & 20 deletions Marlin/src/feature/bltouch.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,37 +26,71 @@
// BLTouch commands are sent as servo angles
typedef unsigned char BLTCommand;

#define BLTOUCH_DEPLOY 10
#define BLTOUCH_SW_MODE 60
#define BLTOUCH_STOW 90
#define BLTOUCH_SELFTEST 120
#define BLTOUCH_5V_MODE 140
#define BLTOUCH_OD_MODE 150
#define BLTOUCH_RESET 160
#define BLTOUCH_DEPLOY 10
#define BLTOUCH_SW_MODE 60
#define BLTOUCH_STOW 90
#define BLTOUCH_SELFTEST 120
#define BLTOUCH_5V_MODE 140
#define BLTOUCH_OD_MODE 150
#define BLTOUCH_RESET 160

// Note: BLTOUCH_DELAY from configuration.h will override these values IF it is larger.
// See command() in bltouch.cpp for more details
// Delay for all commands other then the exceptions below
#define BLTOUCH_CMDMIN_DELAY 150
// The following delays are needed for some of the commands, instead of the CMDMIN_DELAY
#define BLTOUCH_RESET_DELAY 500
#define BLTOUCH_SET5V_DELAY 2000 // This is according to ANTClabs. Seems a bit high???
#define BLTOUCH_SETOD_DELAY 2000 // Probably also according to ANTClabs. Seems a bit high???

// Set the following to zero for highspeed probing mode. Works fine, but does not catch deploy or stow
// errors after the command - instead the error catching is deferred to the subsequent command. Printer
// won't stop, instead it will skip the failed probes. If you consider your probe to be reliable beyond
// a doubt, you can run this way. Not recommended but YMMV
#if ENABLED(BLTOUCH_HS_MODE)
// So we probably won't recognize DEPLOY fails right away
#define BLTOUCH_DEPLOY_DELAY BLTOUCH_CMDMIN_DELAY
#define BLTOUCH_STOW_DELAY BLTOUCH_CMDMIN_DELAY
#undef BLTOUCH_DELAY
#define BLTOUCH_DELAY BLTOUCH_CMDMIN_DELAY
#else
// So that we can recognize DEPLOY fails
#define BLTOUCH_DEPLOY_DELAY 750
#define BLTOUCH_STOW_DELAY 750
#endif

class BLTouch {
public:
static void init();
static void command(const BLTCommand cmd);
static bool triggered();
static bool triggered(); // used by menu_advanced.cpp
static void init(); // used by main.cpp

FORCE_INLINE static void reset() { command(BLTOUCH_RESET); }
FORCE_INLINE static void selftest() { command(BLTOUCH_SELFTEST); }
// DEPLOY and STOW are wrapped for error handling - these are used by homing and by probing
FORCE_INLINE static bool deploy() { return deploy_wrapper(); }
FORCE_INLINE static bool stow() { return stow_wrapper(); }

FORCE_INLINE static void set_5V_mode() { command(BLTOUCH_5V_MODE); }
FORCE_INLINE static void set_OD_mode() { command(BLTOUCH_OD_MODE); }
FORCE_INLINE static void set_SW_mode() { command(BLTOUCH_SW_MODE); }
// Native BLTouch commands ("Underscore"...), used in lcd menus and internally
FORCE_INLINE static void _reset() { command(BLTOUCH_RESET, BLTOUCH_RESET_DELAY); }

FORCE_INLINE static bool deploy() { return set_deployed(true); }
FORCE_INLINE static bool stow() { return set_deployed(false); }
FORCE_INLINE static void _selftest() { command(BLTOUCH_SELFTEST, BLTOUCH_CMDMIN_DELAY); }

FORCE_INLINE static void _deploy() { command(BLTOUCH_DEPLOY); }
FORCE_INLINE static void _stow() { command(BLTOUCH_STOW); }
FORCE_INLINE static void _set_SW_mode() { command(BLTOUCH_SW_MODE, BLTOUCH_CMDMIN_DELAY); }
FORCE_INLINE static void _set_5V_mode() { command(BLTOUCH_5V_MODE, BLTOUCH_SET5V_DELAY); }
FORCE_INLINE static void _set_OD_mode() { command(BLTOUCH_OD_MODE, BLTOUCH_SETOD_DELAY); }

FORCE_INLINE static void _deploy() { command(BLTOUCH_DEPLOY, BLTOUCH_DEPLOY_DELAY); }
FORCE_INLINE static void _stow() { command(BLTOUCH_STOW, BLTOUCH_STOW_DELAY); }

private:
static bool set_deployed(const bool deploy);
FORCE_INLINE static bool _deploy_query_alarm() { return command(BLTOUCH_DEPLOY, BLTOUCH_DEPLOY_DELAY); }
FORCE_INLINE static bool _stow_query_alarm() { return command(BLTOUCH_STOW, BLTOUCH_STOW_DELAY); }

static void clear();
static bool command(const BLTCommand cmd, millis_t ms);
static bool deploy_wrapper();
static bool stow_wrapper();
};

// This transfers the two needed angle values to the servo.cpp/servo.h routine
#define BLTOUCH_ANGLES { BLTOUCH_DEPLOY, BLTOUCH_STOW }

extern BLTouch bltouch;
3 changes: 2 additions & 1 deletion Marlin/src/gcode/calibrate/G28.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,8 @@ void GcodeSuite::G28(const bool always_home_all) {
#endif

#if ENABLED(BLTOUCH)
bltouch.init();
// It is safer to home with a stowed probe
bltouch.stow();
#endif

// Always home with tool 0 active
Expand Down
1 change: 0 additions & 1 deletion Marlin/src/gcode/calibrate/G34_M422.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ void GcodeSuite::G34() {
#endif

#if ENABLED(BLTOUCH)
bltouch.reset();
bltouch.stow();
#endif

Expand Down
2 changes: 1 addition & 1 deletion Marlin/src/lcd/language/language_en.h
Original file line number Diff line number Diff line change
Expand Up @@ -898,7 +898,7 @@
#define MSG_BLTOUCH_DEPLOY _UxGT("Deploy BLTouch")
#endif
#ifndef MSG_BLTOUCH_SW_MODE
#define MSG_BLTOUCH_SW_MODE _UxGT("SW Deploy BLTouch")
#define MSG_BLTOUCH_SW_MODE _UxGT("BLTouch SW Mode")
#endif
#ifndef MSG_BLTOUCH_5V_MODE
#define MSG_BLTOUCH_5V_MODE _UxGT("BLTouch 5V Mode")
Expand Down
13 changes: 7 additions & 6 deletions Marlin/src/lcd/menu/menu_configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,14 +174,15 @@ static void lcd_factory_settings() {
void menu_bltouch() {
START_MENU();
MENU_BACK(MSG_MAIN);
MENU_ITEM(function, MSG_BLTOUCH_RESET, bltouch.reset);
MENU_ITEM(function, MSG_BLTOUCH_SELFTEST, bltouch.selftest);
MENU_ITEM(function, MSG_BLTOUCH_DEPLOY, bltouch._deploy);
// We offer the NATIVE, unwrapped BLTouch commands to the user
MENU_ITEM(function, MSG_BLTOUCH_RESET, bltouch._reset);
MENU_ITEM(function, MSG_BLTOUCH_SELFTEST, bltouch._selftest);
MENU_ITEM(function, MSG_BLTOUCH_STOW, bltouch._stow);
MENU_ITEM(function, MSG_BLTOUCH_DEPLOY, bltouch._deploy);
MENU_ITEM(function, MSG_BLTOUCH_SW_MODE, bltouch._set_SW_mode);
#if ENABLED(BLTOUCH_V3)
MENU_ITEM(function, MSG_BLTOUCH_SW_MODE, bltouch.set_SW_mode);
MENU_ITEM(function, MSG_BLTOUCH_5V_MODE, bltouch.set_5V_mode);
MENU_ITEM(function, MSG_BLTOUCH_OD_MODE, bltouch.set_OD_mode);
MENU_ITEM(function, MSG_BLTOUCH_5V_MODE, bltouch._set_5V_mode);
MENU_ITEM(function, MSG_BLTOUCH_OD_MODE, bltouch._set_OD_mode);
#endif
END_MENU();
}
Expand Down
Loading