bl_iot_sdk/components/bl602/bl602_wifidrv/bl60x_wifi_driver/stateMachine.c
2020-10-26 20:35:25 +08:00

213 lines
7.2 KiB
C

/*
* Copyright (c) 2020 Bouffalolab.
*
* This file is part of
* *** Bouffalolab Software Dev Kit ***
* (see www.bouffalolab.com).
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of Bouffalo Lab nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 2013 Andreas Misje
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "stateMachine.h"
static void goToErrorState( struct stateMachine *stateMachine,
struct event *const event );
static struct transition *getTransition( struct stateMachine *stateMachine,
const struct state *state, struct event *const event );
void stateM_init( struct stateMachine *fsm,
const struct state *initialState, const struct state *errorState )
{
if ( !fsm )
return;
fsm->currentState = initialState;
fsm->previousState = NULL;
fsm->errorState = errorState;
}
int stateM_handleEvent( struct stateMachine *fsm,
struct event *event )
{
if ( !fsm || !event )
return stateM_errArg;
if ( !fsm->currentState )
{
goToErrorState( fsm, event );
return stateM_errorStateReached;
}
if ( !fsm->currentState->numTransitions )
return stateM_noStateChange;
const struct state *nextState = fsm->currentState;
do {
struct transition *transition = getTransition( fsm, nextState, event );
/* If there were no transitions for the given event for the current
* state, check if there are any transitions for any of the parent
* states (if any): */
if ( !transition )
{
nextState = nextState->parentState;
continue;
}
/* A transition must have a next state defined. If the user has not
* defined the next state, go to error state: */
if ( !transition->nextState )
{
goToErrorState( fsm, event );
return stateM_errorStateReached;
}
nextState = transition->nextState;
/* If the new state is a parent state, enter its entry state (if it has
* one). Step down through the whole family tree until a state without
* an entry state is found: */
while ( nextState->entryState )
nextState = nextState->entryState;
/* Run exit action only if the current state is left (only if it does
* not return to itself): */
if ( nextState != fsm->currentState && fsm->currentState->exitAction )
fsm->currentState->exitAction( fsm->currentState->data, event );
/* Run transition action (if any): */
if ( transition->action )
transition->action( fsm->currentState->data, event, nextState->
data );
/* Call the new state's entry action if it has any (only if state does
* not return to itself): */
if ( nextState != fsm->currentState && nextState->entryAction )
nextState->entryAction( nextState->data, event );
fsm->previousState = fsm->currentState;
fsm->currentState = nextState;
/* If the state returned to itself: */
if ( fsm->currentState == fsm->previousState )
return stateM_stateLoopSelf;
if ( fsm->currentState == fsm->errorState )
return stateM_errorStateReached;
/* If the new state is a final state, notify user that the state
* machine has stopped: */
if ( !fsm->currentState->numTransitions )
return stateM_finalStateReached;
return stateM_stateChanged;
} while ( nextState );
return stateM_noStateChange;
}
const struct state *stateM_currentState( struct stateMachine *fsm )
{
if ( !fsm )
return NULL;
return fsm->currentState;
}
const struct state *stateM_previousState( struct stateMachine *fsm )
{
if ( !fsm )
return NULL;
return fsm->previousState;
}
static void goToErrorState( struct stateMachine *fsm,
struct event *const event )
{
fsm->previousState = fsm->currentState;
fsm->currentState = fsm->errorState;
if ( fsm->currentState && fsm->currentState->entryAction )
fsm->currentState->entryAction( fsm->currentState->data, event );
}
static struct transition *getTransition( struct stateMachine *fsm,
const struct state *state, struct event *const event )
{
size_t i;
for ( i = 0; i < state->numTransitions; ++i )
{
struct transition *t = &state->transitions[ i ];
/* A transition for the given event has been found: */
if ( t->eventType == event->type )
{
if ( !t->guard )
return t;
/* If transition is guarded, ensure that the condition is held: */
else if ( t->guard( t->condition, event ) )
return t;
}
}
/* No transitions found for given event for given state: */
return NULL;
}
bool stateM_stopped( struct stateMachine *stateMachine )
{
if ( !stateMachine )
return true;
return stateMachine->currentState->numTransitions == 0;
}