mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-02-21 03:40:47 +00:00
btstack_hsm: rework dispatch code
This commit is contained in:
parent
1a8c51728a
commit
9c79bc9b1a
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user