Compare commits
1 Commits
086e5fe751
...
693517cc8f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
693517cc8f |
@@ -85,17 +85,24 @@ class state{
|
|||||||
this.emitter.emit("movementComplete", { position: targetPosition });
|
this.emitter.emit("movementComplete", { position: targetPosition });
|
||||||
await this.transitionToState("operational");
|
await this.transitionToState("operational");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Abort path: return to 'operational' so a subsequent shutdown/emergency
|
// Abort path: only return to 'operational' when explicitly requested
|
||||||
// sequence can proceed. Without this, the FSM remains stuck in
|
// (shutdown/emergency-stop needs it to unblock the FSM). Routine MGC
|
||||||
// accelerating/decelerating and blocks stopping/idle transitions.
|
// demand-update aborts must NOT auto-transition — doing so causes a
|
||||||
|
// bounce loop where every tick aborts → operational → new move →
|
||||||
|
// abort → operational → ... and the pump never reaches its setpoint.
|
||||||
const msg = typeof error === 'string' ? error : error?.message;
|
const msg = typeof error === 'string' ? error : error?.message;
|
||||||
if (msg === 'Transition aborted' || msg === 'Movement aborted') {
|
if (msg === 'Transition aborted' || msg === 'Movement aborted') {
|
||||||
this.logger.debug(`Movement aborted; returning to 'operational' to unblock further transitions.`);
|
if (this._returnToOperationalOnAbort) {
|
||||||
try {
|
this.logger.debug(`Movement aborted; returning to 'operational' (requested by caller).`);
|
||||||
await this.transitionToState("operational");
|
try {
|
||||||
} catch (e) {
|
await this.transitionToState("operational");
|
||||||
this.logger.debug(`Post-abort transition to operational failed: ${e?.message || e}`);
|
} catch (e) {
|
||||||
|
this.logger.debug(`Post-abort transition to operational failed: ${e?.message || e}`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.logger.debug(`Movement aborted; staying in current state (routine abort).`);
|
||||||
}
|
}
|
||||||
|
this._returnToOperationalOnAbort = false;
|
||||||
this.emitter.emit("movementAborted", { position: targetPosition });
|
this.emitter.emit("movementAborted", { position: targetPosition });
|
||||||
} else {
|
} else {
|
||||||
this.logger.error(error);
|
this.logger.error(error);
|
||||||
@@ -105,9 +112,19 @@ class state{
|
|||||||
|
|
||||||
// -------- State Transition Methods -------- //
|
// -------- State Transition Methods -------- //
|
||||||
|
|
||||||
abortCurrentMovement(reason = "group override") {
|
/**
|
||||||
|
* @param {string} reason - human-readable abort reason
|
||||||
|
* @param {object} [options]
|
||||||
|
* @param {boolean} [options.returnToOperational=false] - when true the FSM
|
||||||
|
* transitions back to 'operational' after the abort so a subsequent
|
||||||
|
* shutdown/emergency-stop sequence can proceed. Set to false (default)
|
||||||
|
* for routine demand updates where the caller will send a new movement
|
||||||
|
* immediately — auto-transitioning would cause a bounce loop.
|
||||||
|
*/
|
||||||
|
abortCurrentMovement(reason = "group override", options = {}) {
|
||||||
if (this.abortController && !this.abortController.signal.aborted) {
|
if (this.abortController && !this.abortController.signal.aborted) {
|
||||||
this.logger.warn(`Aborting movement: ${reason}`);
|
this.logger.warn(`Aborting movement: ${reason}`);
|
||||||
|
this._returnToOperationalOnAbort = Boolean(options.returnToOperational);
|
||||||
this.abortController.abort();
|
this.abortController.abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user