mirror of
https://github.com/grblHAL/core.git
synced 2026-08-17 08:31:43 +08:00
Reworked feed mode handling (G93-G95), now keeps current feed rate over spindle synced motion. Ref. issue #954.
Added P-word option to G38.x probe commands, use to temporarily switch the probe input when multiple probes are available. Fixed PWM spindle ramping, did not hit the target RPM.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
## grblHAL ##
|
||||
|
||||
Latest build date is 202603416, see the [changelog](changelog.md) for details.
|
||||
Latest build date is 20260518, see the [changelog](changelog.md) for details.
|
||||
|
||||
> [!NOTE]
|
||||
> A settings reset will be performed on an update of builds prior to 20241208. Backup and restore of settings is recommended.
|
||||
|
||||
@@ -1,5 +1,34 @@
|
||||
## grblHAL changelog
|
||||
|
||||
<a name="20260518">20260518
|
||||
|
||||
Drivers:
|
||||
|
||||
* Reworked feed mode handling (G93-G95), now keeps current feed rate over spindle synced motion. Ref. issue [#954](https://github.com/grblHAL/core/issues/954).
|
||||
|
||||
* Added P-word option to `G38.x` probe commands, use to temporarily switch the probe input when multiple probes are available.
|
||||
The `P` value is the probe id: `0` - primary probe, `1` - toolsetter, `2` - secondary probe.
|
||||
> [!NOTE]
|
||||
> If probing at the toolsetter \(G59.3 position\) and the `$65 option` _Auto select toolsetter_ is enabled the toolsetter input will be used regardless.
|
||||
|
||||
* Fixed PWM spindle ramping, did not hit the target RPM.
|
||||
|
||||
Drivers:
|
||||
|
||||
* Added link to [new driver](https://github.com/hoshigarasu/grblHAL-STM32U585) for STM32U585 \(Arduino UNO Q\).
|
||||
|
||||
* STM32F7xx: fix for not handling non-interrupt capable probe pins correctly. Ref. STM32H7xx [issue 65](https://github.com/dresco/STM32H7xx/issues/65).
|
||||
|
||||
Plugins:
|
||||
|
||||
* Misc, eventout: fix to make it work with all port configurations. Ref. [issue comment](https://github.com/grblHAL/core/discussions/645#discussioncomment-16921652).
|
||||
|
||||
* Networking: exposed TX buffer bytes remaining to the stream API.
|
||||
|
||||
* SD card: increased ymodem input buffer to make it work with networking protocols.
|
||||
|
||||
---
|
||||
|
||||
<a name="20260511">20260511
|
||||
|
||||
Drivers:
|
||||
|
||||
@@ -1128,6 +1128,9 @@ Useful for some pre-built electronic boards.
|
||||
#if !defined DEFAULT_PWM_SPINDLE_ENABLE_RAMP || defined __DOXYGEN__
|
||||
#define DEFAULT_PWM_SPINDLE_ENABLE_RAMP Off
|
||||
#endif
|
||||
#if !defined DEFAULT_PWM_SPINDLE_IGNORE_DELAYS || defined __DOXYGEN__
|
||||
#define DEFAULT_PWM_SPINDLE_IGNORE_DELAYS Off
|
||||
#endif
|
||||
///@}
|
||||
|
||||
/*! @name $16 - Setting_SpindleInvertMask
|
||||
@@ -1335,6 +1338,23 @@ Defines the parameters for the fourth entry in the spindle RPM linearization tab
|
||||
|
||||
// Settings for second PWM spindle
|
||||
|
||||
/*! @name $709 - Setting_SpindlePWMOptions1
|
||||
*/
|
||||
///@{
|
||||
#if !defined DEFAULT_PWM_SPINDLE1_ENABLE_OFF_WITH_ZERO_SPEED || defined __DOXYGEN__
|
||||
#define DEFAULT_PWM_SPINDLE1_ENABLE_OFF_WITH_ZERO_SPEED Off
|
||||
#endif
|
||||
#if !defined DEFAULT_PWM_SPINDLE1_DISABLE_LASER_MODE || defined __DOXYGEN__
|
||||
#define DEFAULT_PWM_SPINDLE1_DISABLE_LASER_MODE Off
|
||||
#endif
|
||||
#if !defined DEFAULT_PWM_SPINDLE1_ENABLE_RAMP || defined __DOXYGEN__
|
||||
#define DEFAULT_PWM_SPINDLE1_ENABLE_RAMP Off
|
||||
#endif
|
||||
#if !defined DEFAULT_PWM_SPINDLE1_IGNORE_DELAYS || defined __DOXYGEN__
|
||||
#define DEFAULT_PWM_IGNORE_SPINDLE1_DELAYS Off
|
||||
#endif
|
||||
///@}
|
||||
|
||||
/*! @name $716 - Setting_SpindleInvertMask1
|
||||
Inverts the selected spindle output signals from active high to active low. Useful for some pre-built electronic boards.
|
||||
*/
|
||||
|
||||
@@ -2324,62 +2324,60 @@ status_code_t gc_execute_block (char *block)
|
||||
|
||||
// [1. Comments ]: MSG's may be supported by driver layer. Comment handling performed by protocol.
|
||||
|
||||
// [2. Set feed rate mode ]: G93 F word missing with G1,G2/3 active, implicitly or explicitly. Feed rate
|
||||
// is not defined after switching between G93, G94 and G95.
|
||||
// [2. Set feed rate mode ]: G93 F word missing with G1,G2/3 active, implicitly or explicitly.
|
||||
// Feed rate is not defined after switching between G93, G94 and G95.
|
||||
// NOTE: For jogging, ignore prior feed rate mode. Enforce G94 and check for required F word.
|
||||
if(gc_parser_flags.jog_motion) {
|
||||
if(!gc_parser_flags.jog_motion) {
|
||||
|
||||
if(!gc_block.words.f)
|
||||
RETURN(Status_GcodeUndefinedFeedRate);
|
||||
// Switching to G94 or G95 from G93, so don't push last state feed rate.
|
||||
if(gc_block.modal.feed_mode != gc_state.modal.feed_mode)
|
||||
gc_state.feed_rate = 0.0f;
|
||||
|
||||
if(gc_block.modal.feed_mode == FeedMode_InverseTime) { // = G93
|
||||
|
||||
// NOTE: G38 can also operate in inverse time, but is undefined as an error. Missing F word check added here.
|
||||
if(!gc_block.words.f && axis_command == AxisCommand_MotionMode &&
|
||||
!(gc_block.modal.motion == MotionMode_None ||
|
||||
gc_block.modal.motion == MotionMode_Seek ||
|
||||
gc_block.modal.motion == MotionMode_SpindleSynchronized ||
|
||||
gc_block.modal.motion == MotionMode_RigidTapping))
|
||||
RETURN(Status_GcodeUndefinedFeedRate); // [F word missing]
|
||||
|
||||
// NOTE: It seems redundant to check for an F word to be passed after switching from G94 to G93. We would
|
||||
// accomplish the exact same thing if the feed rate value is always reset to zero and undefined after each
|
||||
// inverse time block, since the commands that use this value already perform undefined checks. This would
|
||||
// also allow other commands, following this switch, to execute and not error out needlessly. This code is
|
||||
// combined with the above feed rate mode and the below set feed rate error-checking.
|
||||
|
||||
// - In inverse time mode: Always implicitly zero the feed rate value before and after block completion.
|
||||
// NOTE: If in G93 mode or switched into it from G94, just keep F value as initialized zero or passed F word
|
||||
// value in the block. If no F word is passed with a motion command that requires a feed rate, this will error
|
||||
// out in the motion modes error-checking. However, if no F word is passed with NO motion command that requires
|
||||
// a feed rate, we simply move on and the state feed rate value gets updated to zero and remains undefined.
|
||||
|
||||
} else if(!gc_block.words.f)
|
||||
gc_block.values.f = gc_state.feed_rate; // Push last state feed rate
|
||||
|
||||
} else if(!gc_block.words.f)
|
||||
RETURN(Status_GcodeUndefinedFeedRate);
|
||||
|
||||
// [3. Set feed rate ]:
|
||||
// if F word passed, ensure value is in mm/min or mm/rev depending on mode.
|
||||
if(gc_block.words.f) {
|
||||
if(gc_block.values.f < 0.0f)
|
||||
RETURN(Status_NegativeValue); // [Word value cannot be negative]
|
||||
|
||||
if(gc_block.modal.units_imperial)
|
||||
if(gc_block.modal.feed_mode != FeedMode_InverseTime && gc_block.modal.units_imperial)
|
||||
gc_block.values.f *= MM_PER_INCH;
|
||||
}
|
||||
|
||||
} else if(gc_block.modal.motion == MotionMode_SpindleSynchronized) {
|
||||
|
||||
if (!gc_block.words.k) {
|
||||
if(gc_block.modal.motion == MotionMode_SpindleSynchronized || gc_block.modal.motion == MotionMode_RigidTapping) {
|
||||
if(!gc_block.words.k) {
|
||||
gc_block.values.k = gc_state.distance_per_rev;
|
||||
} else {
|
||||
gc_block.words.k = Off;
|
||||
gc_block.values.k = gc_block.modal.units_imperial ? gc_block.values.ijk[K_VALUE] *= MM_PER_INCH : gc_block.values.ijk[K_VALUE];
|
||||
}
|
||||
|
||||
} else if (gc_block.modal.feed_mode == FeedMode_InverseTime) { // = G93
|
||||
// NOTE: G38 can also operate in inverse time, but is undefined as an error. Missing F word check added here.
|
||||
if (axis_command == AxisCommand_MotionMode) {
|
||||
if (!(gc_block.modal.motion == MotionMode_None || gc_block.modal.motion == MotionMode_Seek)) {
|
||||
if (!gc_block.words.f)
|
||||
RETURN(Status_GcodeUndefinedFeedRate); // [F word missing]
|
||||
}
|
||||
}
|
||||
// NOTE: It seems redundant to check for an F word to be passed after switching from G94 to G93. We would
|
||||
// accomplish the exact same thing if the feed rate value is always reset to zero and undefined after each
|
||||
// inverse time block, since the commands that use this value already perform undefined checks. This would
|
||||
// also allow other commands, following this switch, to execute and not error out needlessly. This code is
|
||||
// combined with the above feed rate mode and the below set feed rate error-checking.
|
||||
|
||||
// [3. Set feed rate ]: F is negative (done.)
|
||||
// - In inverse time mode: Always implicitly zero the feed rate value before and after block completion.
|
||||
// NOTE: If in G93 mode or switched into it from G94, just keep F value as initialized zero or passed F word
|
||||
// value in the block. If no F word is passed with a motion command that requires a feed rate, this will error
|
||||
// out in the motion modes error-checking. However, if no F word is passed with NO motion command that requires
|
||||
// a feed rate, we simply move on and the state feed rate value gets updated to zero and remains undefined.
|
||||
|
||||
} else if (gc_block.modal.feed_mode == FeedMode_UnitsPerMin || gc_block.modal.feed_mode == FeedMode_UnitsPerRev) {
|
||||
// if F word passed, ensure value is in mm/min or mm/rev depending on mode, otherwise push last state value.
|
||||
if (!gc_block.words.f) {
|
||||
if(gc_block.modal.feed_mode == gc_state.modal.feed_mode)
|
||||
gc_block.values.f = gc_state.feed_rate; // Push last state feed rate
|
||||
} else {
|
||||
if(gc_block.values.f < 0.0f)
|
||||
RETURN(Status_NegativeValue); // [Word value cannot be negative]
|
||||
if(gc_block.modal.units_imperial)
|
||||
gc_block.values.f *= MM_PER_INCH;
|
||||
}
|
||||
} // else, switching to G94 from G93, so don't push last state feed rate. Its undefined or the passed F word value.
|
||||
}
|
||||
|
||||
// bit_false(gc_block.words,bit(Word_F)); // NOTE: Single-meaning value word. Set at end of error-checking.
|
||||
|
||||
@@ -3685,16 +3683,36 @@ status_code_t gc_execute_block (char *block)
|
||||
|
||||
case MotionMode_ProbeToward:
|
||||
case MotionMode_ProbeAway:
|
||||
if(gc_block.modal.motion == MotionMode_ProbeAway || gc_block.modal.motion == MotionMode_ProbeAwayNoError)
|
||||
gc_parser_flags.probe_is_away = On;
|
||||
gc_parser_flags.probe_is_away = gc_block.modal.motion == MotionMode_ProbeAway || gc_block.modal.motion == MotionMode_ProbeAwayNoError;
|
||||
// [G38 Errors]: Target is same current. No axis words. Cutter compensation is enabled. Feed rate
|
||||
// is undefined. Probe is triggered. NOTE: Probe check moved to probe cycle. Instead of returning
|
||||
// an error, it issues an alarm to prevent further motion to the probe. It's also done there to
|
||||
// allow the planner buffer to empty and move off the probe trigger before another probing cycle.
|
||||
if (!axis_words.mask)
|
||||
if(!axis_words.mask)
|
||||
RETURN(Status_GcodeNoAxisWords); // [No axis words]
|
||||
if (isequal_position_vector(gc_state.position, gc_block.values.xyz))
|
||||
|
||||
if(isequal_position_vector(gc_state.position, gc_block.values.xyz))
|
||||
RETURN(Status_GcodeInvalidTarget); // [Invalid target]
|
||||
|
||||
if(gc_block.words.p) {
|
||||
if(hal.probe.select) switch((int32_t)gc_block.values.p) {
|
||||
|
||||
case Probe_Default:
|
||||
gc_block.select_probe = hal.driver_cap.probe;
|
||||
break;
|
||||
|
||||
case Probe_Toolsetter:
|
||||
gc_block.select_probe = hal.driver_cap.toolsetter;
|
||||
break;
|
||||
|
||||
case Probe_2:
|
||||
gc_block.select_probe = hal.driver_cap.probe2;
|
||||
break;
|
||||
}
|
||||
if(gc_block.values.p != 0.0f && !gc_block.select_probe)
|
||||
RETURN(Status_GcodeValueOutOfRange); // [Invalid probe]
|
||||
gc_block.words.p = Off;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -4513,10 +4531,23 @@ status_code_t gc_execute_block (char *block)
|
||||
case MotionMode_ProbeTowardNoError:
|
||||
case MotionMode_ProbeAway:
|
||||
case MotionMode_ProbeAwayNoError:
|
||||
// NOTE: gc_block.values.xyz is returned from mc_probe_cycle with the updated position value. So
|
||||
// upon a successful probing cycle, the machine position and the returned value should be the same.
|
||||
plan_data.condition.no_feed_override = !settings.probe.allow_feed_override;
|
||||
gc_update_pos = (pos_update_t)mc_probe_cycle(gc_block.values.xyz, &plan_data, gc_parser_flags);
|
||||
{
|
||||
// NOTE: gc_block.values.xyz is returned from mc_probe_cycle with the updated position value. So
|
||||
// upon a successful probing cycle, the machine position and the returned value should be the same.
|
||||
probe_id_t probe_id;
|
||||
plan_data.condition.no_feed_override = !settings.probe.allow_feed_override;
|
||||
if(gc_block.select_probe){
|
||||
if((gc_block.select_probe = (probe_id_t)gc_block.values.p != (probe_id = hal.probe.get_state().probe_id))) {
|
||||
hal.probe.select((probe_id_t)gc_block.values.p);
|
||||
report_add_realtime(Report_ProbeId);
|
||||
}
|
||||
}
|
||||
gc_update_pos = (pos_update_t)mc_probe_cycle(gc_block.values.xyz, &plan_data, gc_parser_flags);
|
||||
if(gc_block.select_probe) {
|
||||
hal.probe.select(probe_id);
|
||||
report_add_realtime(Report_ProbeId);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -683,6 +683,7 @@ typedef struct {
|
||||
uint32_t arc_turns; //
|
||||
parameter_words_t g65_words; //!< Parameter words to pass to G65 macro.
|
||||
macro_call_t macro_call;
|
||||
bool select_probe; // Set to \a true if the probe has to be selected before executing G38.x.
|
||||
#if NGC_PARAMETERS_ENABLE
|
||||
modal_state_action_t state_action; //!< M70-M73 modal state action
|
||||
#endif
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
#else
|
||||
#define GRBL_VERSION "1.1f"
|
||||
#endif
|
||||
#define GRBL_BUILD 20260506
|
||||
#define GRBL_BUILD 20260518
|
||||
|
||||
#define GRBL_URL "https://github.com/grblHAL"
|
||||
|
||||
|
||||
@@ -472,6 +472,13 @@ static float _get_value (io_port_cfg_t *p, uint8_t port)
|
||||
return port > p->port_max ? -1.0f : (float)port;
|
||||
}
|
||||
|
||||
/*! \brief Set $-setting port number.
|
||||
\param p a pointer to a \a io_port_cfg_t struct.
|
||||
\param port a pointer to a port number to set.
|
||||
\param caps as an \a #pin_cap_t union.
|
||||
\param value the required port number or -1 to set the port as not assigned.
|
||||
\returns status_code_t Status_Ok if port is available and capable.
|
||||
*/
|
||||
static status_code_t _set_value (io_port_cfg_t *p, uint8_t *port, pin_cap_t caps, float value)
|
||||
{
|
||||
status_code_t status;
|
||||
@@ -494,6 +501,11 @@ static status_code_t _set_value (io_port_cfg_t *p, uint8_t *port, pin_cap_t caps
|
||||
return status;
|
||||
}
|
||||
|
||||
static xbar_t *_get_info (io_port_cfg_t *p, uint8_t port)
|
||||
{
|
||||
return hal.port.get_pin_info(p->handle->type >> 1, p->handle->type & 1, map_reverse(&ports_cfg[p->handle->type], port));
|
||||
}
|
||||
|
||||
uint8_t _get_next (io_port_cfg_t *p, uint8_t port, const char *description, pin_cap_t caps)
|
||||
{
|
||||
uint8_t px = IOPORT_UNASSIGNED;
|
||||
@@ -539,6 +551,7 @@ FLASHMEM io_port_cfg_t *ioports_cfg (io_port_cfg_t *pp, io_port_type_t type, io_
|
||||
p->port_max = ioport_find_free(type, dir, (pin_cap_t){ .claimable = On }, NULL);
|
||||
p->get_value = _get_value;
|
||||
p->set_value = _set_value;
|
||||
p->get_info = _get_info;
|
||||
p->get_next = _get_next;
|
||||
p->claim = _claim;
|
||||
strcpy((char *)p->port_maxs, uitoa(p->port_max));
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
Part of grblHAL
|
||||
|
||||
Copyright (c) 2021-2025 Terje Io
|
||||
Copyright (c) 2021-2026 Terje Io
|
||||
|
||||
grblHAL is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -198,6 +198,7 @@ struct ioports_handle; // members defined in ioports.c
|
||||
|
||||
typedef status_code_t (*ioport_set_value_ptr)(struct ioports_cfg *p, uint8_t *port, pin_cap_t caps, float value);
|
||||
typedef float (*ioport_get_value_ptr)(struct ioports_cfg *p, uint8_t port);
|
||||
typedef xbar_t *(*ioport_get_info_ptr)(struct ioports_cfg *p, uint8_t port);
|
||||
typedef uint8_t (*ioport_get_next_ptr)(struct ioports_cfg *p, uint8_t port, const char *description, pin_cap_t caps);
|
||||
typedef xbar_t *(*ioport_claim_ptr)(struct ioports_cfg *p, uint8_t *port, const char *description, pin_cap_t caps);
|
||||
|
||||
@@ -208,6 +209,7 @@ struct ioports_cfg {
|
||||
const char port_maxs[4];
|
||||
ioport_get_value_ptr get_value;
|
||||
ioport_set_value_ptr set_value;
|
||||
ioport_get_info_ptr get_info;
|
||||
ioport_get_next_ptr get_next;
|
||||
ioport_claim_ptr claim;
|
||||
};
|
||||
|
||||
@@ -201,6 +201,7 @@ PROGMEM const settings_t defaults = {
|
||||
.pwm_spindle.flags.enable_rpm_controlled = DEFAULT_SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED,
|
||||
.pwm_spindle.flags.laser_mode_disable = DEFAULT_PWM_SPINDLE_DISABLE_LASER_MODE,
|
||||
.pwm_spindle.flags.pwm_ramped = DEFAULT_PWM_SPINDLE_ENABLE_RAMP,
|
||||
.pwm_spindle.flags.ignore_delays = DEFAULT_PWM_SPINDLE_IGNORE_DELAYS,
|
||||
.pwm_spindle.invert.on = DEFAULT_INVERT_SPINDLE_ENABLE_PIN,
|
||||
.pwm_spindle.invert.ccw = DEFAULT_INVERT_SPINDLE_CCW_PIN,
|
||||
.pwm_spindle.invert.pwm = DEFAULT_INVERT_SPINDLE_PWM_PIN,
|
||||
|
||||
+9
-8
@@ -687,14 +687,14 @@ FLASHMEM static void spindle_ramp (spindle_ptrs_t *spindle, spindle_state_t stat
|
||||
if(ramp.rpm_delta > 0.0f) {
|
||||
if(spindle->param->state.on != state.on || state.ccw != spindle->param->state.ccw) {
|
||||
spindle->param->state.on = state.on;
|
||||
spindle->set_state(spindle, state, (rpm = rpm + ramp.rpm_delta));
|
||||
spindle->set_state(spindle, state, (rpm += ramp.rpm_delta));
|
||||
}
|
||||
while(ok && (rpm = rpm + ramp.rpm_delta) < target_rpm) {
|
||||
spindle->update_pwm(spindle, spindle->get_pwm(spindle, rpm));
|
||||
while(ok && (rpm + ramp.rpm_delta) < target_rpm) {
|
||||
spindle->update_pwm(spindle, spindle->get_pwm(spindle, rpm += ramp.rpm_delta));
|
||||
ok = delay_sec(delay, sys.suspend ? DelayMode_SysSuspend : DelayMode_Dwell);
|
||||
}
|
||||
} else while(ok && (rpm = rpm + ramp.rpm_delta) > target_rpm) {
|
||||
spindle->update_pwm(spindle, spindle->get_pwm(spindle, rpm));
|
||||
} else while(ok && (rpm + ramp.rpm_delta) > target_rpm) {
|
||||
spindle->update_pwm(spindle, spindle->get_pwm(spindle, rpm += ramp.rpm_delta));
|
||||
ok = delay_sec(delay, sys.suspend ? DelayMode_SysSuspend : DelayMode_Dwell);
|
||||
}
|
||||
ramp.end = hal.get_elapsed_ticks();
|
||||
@@ -1323,9 +1323,10 @@ FLASHMEM static void spindle1_settings_restore (void)
|
||||
.rpm_max = DEFAULT_SPINDLE1_RPM_MAX,
|
||||
.rpm_min = DEFAULT_SPINDLE1_RPM_MIN,
|
||||
.flags.pwm_disable = false,
|
||||
.flags.enable_rpm_controlled = 0, //DEFAULT_SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED,
|
||||
.flags.pwm_ramped = DEFAULT_PWM_SPINDLE_ENABLE_RAMP,
|
||||
.flags.laser_mode_disable = 0, // TODO: Not possible?
|
||||
.flags.enable_rpm_controlled = DEFAULT_PWM_SPINDLE1_ENABLE_OFF_WITH_ZERO_SPEED,
|
||||
.flags.laser_mode_disable = DEFAULT_PWM_SPINDLE1_DISABLE_LASER_MODE,
|
||||
.flags.pwm_ramped = DEFAULT_PWM_SPINDLE1_ENABLE_RAMP,
|
||||
.flags.ignore_delays = DEFAULT_PWM_SPINDLE1_IGNORE_DELAYS,
|
||||
.invert.on = DEFAULT_INVERT_SPINDLE1_ENABLE_PIN,
|
||||
.invert.ccw = DEFAULT_INVERT_SPINDLE1_CCW_PIN,
|
||||
.invert.pwm = DEFAULT_INVERT_SPINDLE1_PWM_PIN,
|
||||
|
||||
+14
-9
@@ -255,22 +255,22 @@ void state_set (sys_state_t new_state)
|
||||
break;
|
||||
|
||||
case STATE_CYCLE:
|
||||
if (sys_state == STATE_IDLE) {
|
||||
if(sys_state == STATE_IDLE) {
|
||||
// Start cycle only if queued motions exist in planner buffer and the motion is not canceled.
|
||||
plan_block_t *block;
|
||||
if ((block = plan_get_current_block())) {
|
||||
if((block = plan_get_current_block())) {
|
||||
sys_state = new_state;
|
||||
sys.steppers_deenergize = false; // Cancel stepper deenergize if pending.
|
||||
st_prep_buffer(); // Initialize step segment buffer before beginning cycle.
|
||||
if (block->spindle.state.synchronized) {
|
||||
|
||||
uint32_t ms = hal.get_elapsed_ticks();
|
||||
|
||||
if (block->spindle.hal->reset_data)
|
||||
block->spindle.hal->reset_data();
|
||||
if(block->spindle.state.synchronized) {
|
||||
|
||||
if(!block->condition.units_per_rev) {
|
||||
|
||||
uint32_t ms = hal.get_elapsed_ticks();
|
||||
|
||||
if(block->spindle.hal->reset_data)
|
||||
block->spindle.hal->reset_data();
|
||||
|
||||
uint32_t index = block->spindle.hal->get_data(SpindleData_Counters)->index_count + 2;
|
||||
|
||||
while(index != block->spindle.hal->get_data(SpindleData_Counters)->index_count) {
|
||||
@@ -286,7 +286,12 @@ void state_set (sys_state_t new_state)
|
||||
system_set_exec_state_flag(EXEC_RESET);
|
||||
return;
|
||||
}
|
||||
// TODO: allow real time reporting?
|
||||
/* TODO: allow real time reporting?
|
||||
if(bit_istrue(sys.rt_exec_state, EXEC_STATUS_REPORT)) {
|
||||
system_clear_exec_state_flag(EXEC_STATUS_REPORT);
|
||||
report_realtime_status(hal.stream.write_all, &hal.stream.report);
|
||||
}
|
||||
*/
|
||||
}
|
||||
} else if(block->spindle.hal->get_data(SpindleData_RPM)->rpm == 0.0f) {
|
||||
system_raise_alarm(Alarm_Spindle);
|
||||
|
||||
@@ -201,6 +201,16 @@ FLASHMEM bool stream_rx_suspend (stream_rx_buffer_t *rxbuffer, bool suspend)
|
||||
return ok;
|
||||
}
|
||||
|
||||
FLASHMEM bool stream_await_tx_clear (const io_stream_t *stream)
|
||||
{
|
||||
if(stream->get_tx_buffer_count) {
|
||||
while(stream->get_tx_buffer_count())
|
||||
grbl.on_execute_realtime(state_get());
|
||||
}
|
||||
|
||||
return !!stream->get_tx_buffer_count;
|
||||
}
|
||||
|
||||
ISR_CODE bool ISR_FUNC(stream_buffer_all)(uint8_t c)
|
||||
{
|
||||
return false;
|
||||
@@ -346,9 +356,7 @@ FLASHMEM static bool stream_select (const io_stream_t *stream, bool add)
|
||||
if(active_stream && active_stream->type != StreamType_Serial && connection_is_up((io_stream_t *)stream)) {
|
||||
hal.stream.write = stream->write;
|
||||
report_message("SERIAL STREAM ACTIVE", Message_Plain);
|
||||
if(stream->get_tx_buffer_count)
|
||||
while(stream->get_tx_buffer_count());
|
||||
else
|
||||
if(!stream_await_tx_clear(stream))
|
||||
hal.delay_ms(100, NULL);
|
||||
}
|
||||
break;
|
||||
@@ -854,8 +862,7 @@ void debug_write (const char *s)
|
||||
{
|
||||
if(dbg_write) {
|
||||
dbg_write(s);
|
||||
while(hal.debug.get_tx_buffer_count()) // Wait until message is delivered
|
||||
grbl.on_execute_realtime(state_get());
|
||||
stream_await_tx_clear(&hal.debug); // Wait until message is delivered
|
||||
}
|
||||
}
|
||||
|
||||
@@ -869,9 +876,7 @@ void debug_writeln (const char *s)
|
||||
|
||||
dbg_write(s);
|
||||
dbg_write(ASCII_EOL);
|
||||
|
||||
while(hal.debug.get_tx_buffer_count()) // Wait until message is delivered
|
||||
grbl.on_execute_realtime(state_get());
|
||||
stream_await_tx_clear(&hal.debug); // Wait until message is delivered
|
||||
|
||||
lock = false;
|
||||
}
|
||||
@@ -934,10 +939,7 @@ void debug_printf (const char *fmt, ...)
|
||||
|
||||
if(hal.stream.write) {
|
||||
report_message(debug_out, Message_Debug);
|
||||
if(hal.stream.get_tx_buffer_count) {
|
||||
while(hal.stream.get_tx_buffer_count()) // Wait until message is delivered
|
||||
grbl.on_execute_realtime(state_get());
|
||||
}
|
||||
stream_await_tx_clear(&hal.stream); // Wait until message is delivered
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -500,6 +500,8 @@ void stream_disconnect (const io_stream_t *stream);
|
||||
|
||||
bool stream_connected (void);
|
||||
|
||||
bool stream_await_tx_clear (const io_stream_t *stream);
|
||||
|
||||
void stream_set_defaults (const io_stream_t *stream, uint32_t baud_rate);
|
||||
|
||||
const io_stream_t *stream_get_base (void);
|
||||
|
||||
Reference in New Issue
Block a user