1*bb8a927bSDirk Helbig /* 2*bb8a927bSDirk Helbig * Copyright (C) 2024 BlueKitchen GmbH 3*bb8a927bSDirk Helbig * 4*bb8a927bSDirk Helbig * Redistribution and use in source and binary forms, with or without 5*bb8a927bSDirk Helbig * modification, are permitted provided that the following conditions 6*bb8a927bSDirk Helbig * are met: 7*bb8a927bSDirk Helbig * 8*bb8a927bSDirk Helbig * 1. Redistributions of source code must retain the above copyright 9*bb8a927bSDirk Helbig * notice, this list of conditions and the following disclaimer. 10*bb8a927bSDirk Helbig * 2. Redistributions in binary form must reproduce the above copyright 11*bb8a927bSDirk Helbig * notice, this list of conditions and the following disclaimer in the 12*bb8a927bSDirk Helbig * documentation and/or other materials provided with the distribution. 13*bb8a927bSDirk Helbig * 3. Neither the name of the copyright holders nor the names of 14*bb8a927bSDirk Helbig * contributors may be used to endorse or promote products derived 15*bb8a927bSDirk Helbig * from this software without specific prior written permission. 16*bb8a927bSDirk Helbig * 4. Any redistribution, use, or modification is done solely for 17*bb8a927bSDirk Helbig * personal benefit and not for any commercial purpose or for 18*bb8a927bSDirk Helbig * monetary gain. 19*bb8a927bSDirk Helbig * 20*bb8a927bSDirk Helbig * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21*bb8a927bSDirk Helbig * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22*bb8a927bSDirk Helbig * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23*bb8a927bSDirk Helbig * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 24*bb8a927bSDirk Helbig * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25*bb8a927bSDirk Helbig * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26*bb8a927bSDirk Helbig * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27*bb8a927bSDirk Helbig * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28*bb8a927bSDirk Helbig * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29*bb8a927bSDirk Helbig * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30*bb8a927bSDirk Helbig * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31*bb8a927bSDirk Helbig * SUCH DAMAGE. 32*bb8a927bSDirk Helbig * 33*bb8a927bSDirk Helbig * Please inquire about commercial licensing options at 34*bb8a927bSDirk Helbig * [email protected] 35*bb8a927bSDirk Helbig * 36*bb8a927bSDirk Helbig */ 37*bb8a927bSDirk Helbig #define BTSTACK_FILE__ "btstack_hsm.c" 38*bb8a927bSDirk Helbig 39*bb8a927bSDirk Helbig #include <stddef.h> 40*bb8a927bSDirk Helbig #include <string.h> 41*bb8a927bSDirk Helbig #include <stdbool.h> 42*bb8a927bSDirk Helbig 43*bb8a927bSDirk Helbig #include "btstack_config.h" 44*bb8a927bSDirk Helbig #include "btstack_debug.h" 45*bb8a927bSDirk Helbig 46*bb8a927bSDirk Helbig #include "btstack_hsm.h" 47*bb8a927bSDirk Helbig 48*bb8a927bSDirk Helbig btstack_hsm_state_t btstack_hsm_transit(btstack_hsm_t * const me, btstack_hsm_state_handler_t const target) { 49*bb8a927bSDirk Helbig me->temp = target; 50*bb8a927bSDirk Helbig return BTSTACK_HSM_TRAN_STATUS; 51*bb8a927bSDirk Helbig } 52*bb8a927bSDirk Helbig 53*bb8a927bSDirk Helbig btstack_hsm_state_t btstack_hsm_super(btstack_hsm_t * const me, btstack_hsm_state_handler_t const target) { 54*bb8a927bSDirk Helbig me->temp = target; 55*bb8a927bSDirk Helbig return BTSTACK_HSM_SUPER_STATUS; 56*bb8a927bSDirk Helbig } 57*bb8a927bSDirk Helbig 58*bb8a927bSDirk Helbig btstack_hsm_state_t btstack_hsm_top(btstack_hsm_t * const me, btstack_hsm_event_t const * const e) { 59*bb8a927bSDirk Helbig UNUSED(me); 60*bb8a927bSDirk Helbig UNUSED(e); 61*bb8a927bSDirk Helbig return BTSTACK_HSM_IGNORED_STATUS; 62*bb8a927bSDirk Helbig } 63*bb8a927bSDirk Helbig 64*bb8a927bSDirk Helbig void btstack_hsm_constructor(btstack_hsm_t * const me, btstack_hsm_state_handler_t initial, btstack_hsm_state_handler_t path[], int8_t depth) { 65*bb8a927bSDirk Helbig me->state = btstack_hsm_top; 66*bb8a927bSDirk Helbig me->temp = initial; 67*bb8a927bSDirk Helbig me->path = path; 68*bb8a927bSDirk Helbig me->depth = depth; 69*bb8a927bSDirk Helbig } 70*bb8a927bSDirk Helbig 71*bb8a927bSDirk Helbig static btstack_hsm_state_t btstack_hsm_get_super( btstack_hsm_t * const me, btstack_hsm_state_handler_t const handler) { 72*bb8a927bSDirk Helbig // empty event to trigger default state action, a.k. the super state 73*bb8a927bSDirk Helbig static btstack_hsm_event_t const empty_evt = { BTSTACK_HSM_EMPTY_SIG }; 74*bb8a927bSDirk Helbig return handler( me, &empty_evt ); 75*bb8a927bSDirk Helbig } 76*bb8a927bSDirk Helbig 77*bb8a927bSDirk Helbig static btstack_hsm_event_t const entry_evt = { BTSTACK_HSM_ENTRY_SIG }; 78*bb8a927bSDirk Helbig static btstack_hsm_event_t const exit_evt = { BTSTACK_HSM_EXIT_SIG }; 79*bb8a927bSDirk Helbig 80*bb8a927bSDirk Helbig void btstack_hsm_init(btstack_hsm_t * const me, btstack_hsm_event_t const * const e) { 81*bb8a927bSDirk Helbig btstack_assert(me->state != NULL); 82*bb8a927bSDirk Helbig btstack_assert(me->temp != NULL); 83*bb8a927bSDirk Helbig btstack_hsm_state_handler_t target = me->state; 84*bb8a927bSDirk Helbig btstack_hsm_state_t status = me->temp(me, e); 85*bb8a927bSDirk Helbig btstack_assert( status == BTSTACK_HSM_TRAN_STATUS ); 86*bb8a927bSDirk Helbig static btstack_hsm_event_t const init_evt = { BTSTACK_HSM_INIT_SIG }; 87*bb8a927bSDirk Helbig 88*bb8a927bSDirk Helbig int_fast8_t level; 89*bb8a927bSDirk Helbig btstack_hsm_state_handler_t *root_path = me->path; 90*bb8a927bSDirk Helbig memset(root_path, 0, sizeof(btstack_hsm_state_handler_t)*me->depth); 91*bb8a927bSDirk Helbig 92*bb8a927bSDirk Helbig do { 93*bb8a927bSDirk Helbig level = 0; 94*bb8a927bSDirk Helbig btstack_hsm_state_handler_t current = me->temp; 95*bb8a927bSDirk Helbig for(; current != target; current=me->temp, level++ ) { 96*bb8a927bSDirk Helbig root_path[level] = current; 97*bb8a927bSDirk Helbig btstack_hsm_get_super( me, current ); 98*bb8a927bSDirk Helbig } 99*bb8a927bSDirk Helbig for(; level>0;) { 100*bb8a927bSDirk Helbig root_path[--level]( me, &entry_evt ); 101*bb8a927bSDirk Helbig } 102*bb8a927bSDirk Helbig target = root_path[0]; 103*bb8a927bSDirk Helbig status = target( me, &init_evt ); 104*bb8a927bSDirk Helbig } while (status == BTSTACK_HSM_TRAN_STATUS); 105*bb8a927bSDirk Helbig btstack_assert( status != BTSTACK_HSM_TRAN_STATUS ); 106*bb8a927bSDirk Helbig me->state = target; 107*bb8a927bSDirk Helbig } 108*bb8a927bSDirk Helbig 109*bb8a927bSDirk Helbig 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 ) { 110*bb8a927bSDirk Helbig if( cache[idx] == NULL ) { 111*bb8a927bSDirk Helbig cache[idx] = handler; 112*bb8a927bSDirk Helbig btstack_hsm_get_super(me, handler); 113*bb8a927bSDirk Helbig } else { 114*bb8a927bSDirk Helbig me->temp = cache[idx]; 115*bb8a927bSDirk Helbig } 116*bb8a927bSDirk Helbig } 117*bb8a927bSDirk Helbig 118*bb8a927bSDirk Helbig btstack_hsm_state_t btstack_hsm_dispatch(btstack_hsm_t * const me, btstack_hsm_event_t const * const e) { 119*bb8a927bSDirk Helbig btstack_hsm_state_t status; 120*bb8a927bSDirk Helbig btstack_hsm_state_handler_t current = me->state; 121*bb8a927bSDirk Helbig do { 122*bb8a927bSDirk Helbig status = current(me, e); 123*bb8a927bSDirk Helbig // if the state doesn't handle the event try at the super state too 124*bb8a927bSDirk Helbig if( status == BTSTACK_HSM_UNHANDLED_STATUS ) { 125*bb8a927bSDirk Helbig status = btstack_hsm_get_super( me, current ); 126*bb8a927bSDirk Helbig } 127*bb8a927bSDirk Helbig current = me->temp; 128*bb8a927bSDirk Helbig } while( status == BTSTACK_HSM_SUPER_STATUS ); 129*bb8a927bSDirk Helbig 130*bb8a927bSDirk Helbig // if we don't switch states we are done now 131*bb8a927bSDirk Helbig if( status != BTSTACK_HSM_TRAN_STATUS ) { 132*bb8a927bSDirk Helbig return status; 133*bb8a927bSDirk Helbig } 134*bb8a927bSDirk Helbig btstack_hsm_state_handler_t source = me->state; 135*bb8a927bSDirk Helbig btstack_hsm_state_handler_t target = me->temp; 136*bb8a927bSDirk Helbig btstack_hsm_state_handler_t *root_path = me->path; 137*bb8a927bSDirk Helbig memset(root_path, 0, sizeof(btstack_hsm_state_handler_t)*me->depth); 138*bb8a927bSDirk Helbig 139*bb8a927bSDirk Helbig // why should that be possible/necessary? 140*bb8a927bSDirk Helbig btstack_assert( source != target ); 141*bb8a927bSDirk Helbig 142*bb8a927bSDirk Helbig // handle entry/exit edges 143*bb8a927bSDirk Helbig int_fast8_t level = 0; 144*bb8a927bSDirk Helbig bool lca_found = false; 145*bb8a927bSDirk Helbig // calculates the lowest common ancestor of the state graph 146*bb8a927bSDirk Helbig for(; source != btstack_hsm_top; source=me->temp) { 147*bb8a927bSDirk Helbig level = 0; 148*bb8a927bSDirk Helbig for(current=target; current != btstack_hsm_top; current=me->temp, ++level ) { 149*bb8a927bSDirk Helbig if( current == source ) { 150*bb8a927bSDirk Helbig lca_found = true; 151*bb8a927bSDirk Helbig break; 152*bb8a927bSDirk Helbig } 153*bb8a927bSDirk Helbig 154*bb8a927bSDirk Helbig btstack_hsm_handler_super_cache( me, root_path, level, current ); 155*bb8a927bSDirk Helbig } 156*bb8a927bSDirk Helbig if( lca_found == true ) { 157*bb8a927bSDirk Helbig break; 158*bb8a927bSDirk Helbig } 159*bb8a927bSDirk Helbig source( me, &exit_evt ); 160*bb8a927bSDirk Helbig btstack_hsm_get_super( me, source ); 161*bb8a927bSDirk Helbig } 162*bb8a927bSDirk Helbig 163*bb8a927bSDirk Helbig for(level--; level > 0; ) { 164*bb8a927bSDirk Helbig root_path[--level]( me, &entry_evt ); 165*bb8a927bSDirk Helbig } 166*bb8a927bSDirk Helbig me->state = target; 167*bb8a927bSDirk Helbig return status; 168*bb8a927bSDirk Helbig } 169*bb8a927bSDirk Helbig 170