Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,11 @@ For a successful dispatch:
4. Entry callbacks for the target state.
5. Machine-level transition observers.

`begin(initialState)` invokes entry callbacks for the initial state with `bootstrap=true`. `end()` invokes exit callbacks for the current state with `shutdown=true`.
`begin(initialState)` invokes entry callbacks for the initial state with `bootstrap=true`. `end()` invokes exit callbacks for the current state with `shutdown=true`. If `end()` is requested from inside a callback, shutdown is deferred until the active callback chain completes.

## Runtime Cost
- Dispatch scans registered transitions linearly, and callback/observer invocation scans the registered callback lists linearly.
- Guards, actions, state callbacks, transition observers, and rejection observers are stored as `std::function`; prefer registering them during setup and keep captures small on memory-constrained targets.

## Optional Adapters
### EventBus Bridge
Expand Down
7 changes: 6 additions & 1 deletion src/esp_state_machine/adapters/logger_observer.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,12 @@ template <typename State, typename Event> class ESPStateMachineLoggerObserver {
);
}

return transitionCallbackId_ != 0 && (!options_.logRejected || rejectedCallbackId_ != 0);
if (transitionCallbackId_ == 0 || (options_.logRejected && rejectedCallbackId_ == 0)) {
detach();
return false;
}

return true;
}

void detach() {
Expand Down
54 changes: 40 additions & 14 deletions src/esp_state_machine/state_machine.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ template <typename State, typename Event> class ESPStateMachine {
previousState_ = initialState;
lastStatus_ = StateMachineDispatchStatus::NotStarted;
sequence_ = 0;
stopPending_ = false;
started_ = true;

dispatching_ = true;
Expand All @@ -175,27 +176,23 @@ template <typename State, typename Event> class ESPStateMachine {
context.otherState = initialState;
context.bootstrap = true;
invokeStateCallbacks(enterCallbacks_, initialState, context);
dispatching_ = false;
completeCallbackRun();

return true;
}

void end() {
if (!started_ || dispatching_) {
started_ = false;
if (!started_) {
stopPending_ = false;
return;
}

dispatching_ = true;
StateCallbackContext<State, Event> context{};
context.state = currentState_;
context.otherState = currentState_;
context.sequence = sequence_;
context.shutdown = true;
invokeStateCallbacks(exitCallbacks_, currentState_, context);
dispatching_ = false;
if (dispatching_) {
stopPending_ = true;
return;
}

started_ = false;
runShutdownCallbacks();
}

bool isStarted() const {
Expand Down Expand Up @@ -305,7 +302,7 @@ template <typename State, typename Event> class ESPStateMachine {
result.status = StateMachineDispatchStatus::Transitioned;
result.transitioned = true;
setLastDispatch(event, result.status);
dispatching_ = false;
completeCallbackRun();
return result;
}

Expand All @@ -321,7 +318,7 @@ template <typename State, typename Event> class ESPStateMachine {
rejected.status = result.status;
invokeRejectedObservers(rejected);

dispatching_ = false;
completeCallbackRun();
return result;
}

Expand Down Expand Up @@ -431,6 +428,34 @@ template <typename State, typename Event> class ESPStateMachine {
lastStatus_ = status;
}

void completeCallbackRun() {
dispatching_ = false;
if (stopPending_) {
runShutdownCallbacks();
}
}

void runShutdownCallbacks() {
if (!started_) {
stopPending_ = false;
return;
}

stopPending_ = false;
dispatching_ = true;

StateCallbackContext<State, Event> context{};
context.state = currentState_;
context.otherState = currentState_;
context.sequence = sequence_;
context.shutdown = true;
invokeStateCallbacks(exitCallbacks_, currentState_, context);

dispatching_ = false;
stopPending_ = false;
started_ = false;
}

std::vector<TransitionEntry> transitions_{};
std::vector<StateCallbackEntry> enterCallbacks_{};
std::vector<StateCallbackEntry> exitCallbacks_{};
Expand All @@ -445,4 +470,5 @@ template <typename State, typename Event> class ESPStateMachine {
StateMachineCallbackId nextCallbackId_ = 1;
bool started_ = false;
bool dispatching_ = false;
bool stopPending_ = false;
};
Loading
Loading