btstack_hsm: rework dispatch code

This commit is contained in:
Matthias Ringwald 2024-03-06 11:44:34 +01:00
parent 1a8c51728a
commit 9c79bc9b1a

View File

@ -76,6 +76,7 @@ static btstack_hsm_state_t btstack_hsm_get_super( btstack_hsm_t * const me, btst
static btstack_hsm_event_t const entry_evt = { BTSTACK_HSM_ENTRY_SIG };
static btstack_hsm_event_t const exit_evt = { BTSTACK_HSM_EXIT_SIG };
static btstack_hsm_event_t const init_evt = { BTSTACK_HSM_INIT_SIG };
void btstack_hsm_init(btstack_hsm_t * const me, btstack_hsm_event_t const * const e) {
btstack_assert(me->state != NULL);
@ -83,21 +84,19 @@ void btstack_hsm_init(btstack_hsm_t * const me, btstack_hsm_event_t const * cons
btstack_hsm_state_handler_t target = me->state;
btstack_hsm_state_t status = me->temp(me, e);
btstack_assert( status == BTSTACK_HSM_TRAN_STATUS );
static btstack_hsm_event_t const init_evt = { BTSTACK_HSM_INIT_SIG };
int_fast8_t level;
btstack_hsm_state_handler_t *root_path = me->path;
memset(root_path, 0, sizeof(btstack_hsm_state_handler_t)*me->depth);
do {
level = 0;
int_fast8_t level = 0;
btstack_hsm_state_handler_t current = me->temp;
for(; current != target; current=me->temp, level++ ) {
root_path[level] = current;
btstack_hsm_get_super( me, current );
}
for(; level>0;) {
root_path[--level]( me, &entry_evt );
for(--level; level>=0;--level) {
root_path[level]( me, &entry_evt );
}
target = root_path[0];
status = target( me, &init_evt );
@ -106,10 +105,22 @@ void btstack_hsm_init(btstack_hsm_t * const me, btstack_hsm_event_t const * cons
me->state = target;
}
static void btstack_hsm_handler_super_cache( btstack_hsm_t * const me, btstack_hsm_state_handler_t cache[], int idx, btstack_hsm_state_handler_t handler ) {
if( cache[idx] == NULL ) {
cache[idx] = handler;
static void btstack_hsm_handler_super_cache(
btstack_hsm_t * const me,
btstack_hsm_state_handler_t cache[],
int idx, btstack_hsm_state_handler_t handler ) {
if( idx == me->depth ) {
btstack_hsm_get_super(me, handler);
if( me->temp != btstack_hsm_top ) {
log_error("state machine has higher depth (%d) than specified!", me->depth);
btstack_assert( 0 );
}
return;
}
if( cache[idx] == NULL ) {
btstack_hsm_get_super(me, handler);
cache[idx] = me->temp;
} else {
me->temp = cache[idx];
}
@ -117,34 +128,54 @@ static void btstack_hsm_handler_super_cache( btstack_hsm_t * const me, btstack_h
btstack_hsm_state_t btstack_hsm_dispatch(btstack_hsm_t * const me, btstack_hsm_event_t const * const e) {
btstack_hsm_state_t status;
btstack_hsm_state_handler_t current = me->state;
btstack_hsm_state_handler_t current;
// forward event to next hierarchy level if not handled in current state
me->temp = me->state;
do {
current = me->temp;
status = current(me, e);
// if the state doesn't handle the event try at the super state too
if( status == BTSTACK_HSM_UNHANDLED_STATUS ) {
status = btstack_hsm_get_super( me, current );
}
current = me->temp;
} while( status == BTSTACK_HSM_SUPER_STATUS );
// if we don't switch states we are done now
if( status != BTSTACK_HSM_TRAN_STATUS ) {
return status;
}
btstack_hsm_state_handler_t source = me->state;
btstack_hsm_state_handler_t target = me->temp;
// save the destination of the previous transition
btstack_hsm_state_handler_t dest = me->temp;
// if the transaction came from an higher hierarchical level, go there
btstack_hsm_state_handler_t target = current;
current = me->state;
for(; current != target; current = me->temp) {
current( me, &exit_evt );
btstack_hsm_get_super( me, current );
}
btstack_hsm_state_handler_t source = target;
target = dest;
btstack_hsm_state_handler_t *root_path = me->path;
memset(root_path, 0, sizeof(btstack_hsm_state_handler_t)*me->depth);
// why should that be possible/necessary?
btstack_assert( source != target );
// the state handlers form a single linked list with the default transition pointing to the previous hierarchy level,
// so if we only record the previous pointer we miss the first element of the list to reproduce it fully.
// So now the array contains head->prev->prev->prev...
root_path[0] = target;
// self transition
if( source == target ) {
source( me, &exit_evt );
target( me, &entry_evt );
}
// handle entry/exit edges
int_fast8_t level = 0;
bool lca_found = false;
// calculates the lowest common ancestor of the state graph
for(; source != btstack_hsm_top; source=me->temp) {
level = 0;
level = 1;
for(current=target; current != btstack_hsm_top; current=me->temp, ++level ) {
if( current == source ) {
lca_found = true;
@ -160,8 +191,22 @@ btstack_hsm_state_t btstack_hsm_dispatch(btstack_hsm_t * const me, btstack_hsm_e
btstack_hsm_get_super( me, source );
}
for(level--; level > 0; ) {
root_path[--level]( me, &entry_evt );
// handle entry in reverse order
for(level-=2; level >= 0; --level) {
root_path[level]( me, &entry_evt );
}
// initial transitions are only allowed to point deeper into the state machine hierarchy,
// so we only follow this direction here, deeper.
for(; target( me, &init_evt ) == BTSTACK_HSM_TRAN_STATUS ;) {
current = me->temp;
for(level = 0; current != target; current=me->temp, ++level ) {
root_path[level] = current;
btstack_hsm_get_super( me, current );
}
for(--level; level >= 0; --level) {
root_path[level]( me, &entry_evt );
}
target = root_path[0];
}
me->state = target;
return status;