/*------------------------------------------------------------------------------------------------*/ /* UNICENS V2.1.0-3491 */ /* Copyright (c) 2017 Microchip Technology Germany II GmbH & Co. KG. */ /* */ /* This program is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program. If not, see . */ /* */ /* You may also obtain this software under a propriety license from Microchip. */ /* Please contact Microchip for further information. */ /*------------------------------------------------------------------------------------------------*/ /*! * \file * \brief Implementation of the Finite State Machine. * * \cond UCS_INTERNAL_DOC * \addtogroup G_FSM * @{ */ /*------------------------------------------------------------------------------------------------*/ /* Includes */ /*------------------------------------------------------------------------------------------------*/ #include "ucs_fsm.h" #include "ucs_misc.h" /*------------------------------------------------------------------------------------------------*/ /* Internal definitions */ /*------------------------------------------------------------------------------------------------*/ /*! \brief NIL-event, indicates that no event is pending at the moment */ #define FSM_E_NILEVENT 0 /*------------------------------------------------------------------------------------------------*/ /* Internal prototypes */ /*------------------------------------------------------------------------------------------------*/ static Fsm_Act_t Fsm_StateEval(CFsm *self); /*------------------------------------------------------------------------------------------------*/ /* Implementation */ /*------------------------------------------------------------------------------------------------*/ /*! \brief Constructor of the Finite State Machine class. * \param self Instance pointer * \param inst_ptr Instance pointer used for state machine actions * \param trans_table_ptr Pointer to transition table * \param num_events Maximum number of events * \param init_state Initialization state to start with */ void Fsm_Ctor(CFsm *self, void *inst_ptr, const Fsm_StateElem_t *trans_table_ptr, uint8_t num_events, int8_t init_state) { MISC_MEM_SET(self, 0, sizeof(*self)); self->inst_ptr = inst_ptr; self->event_occured = FSM_E_NILEVENT; /* Clear event variable */ self->current_state = init_state; /* Set initialization state */ self->transition_table_ptr = trans_table_ptr; /* Set pointer to given transition table */ self->num_events = num_events; /* Store maximum number of events */ self->internal_state = FSM_STATE_IDLE; /* Clear internal state */ } /*! \brief Determine required action * \details This function determines the required action in dependency of the current state * and the triggered event. The current state will be transitioned to the next state. * The internal event variable will be cleared and the determined action will be * returned. * \param self Instance pointer * \return Determined required action * \return \c NULL if no action is required */ static Fsm_Act_t Fsm_StateEval(CFsm *self) { Fsm_Act_t retval = NULL; /* Set default return value */ if(self->event_occured != FSM_E_NILEVENT) /* Event occurred ? */ { if((uint8_t)self->event_occured <= self->num_events) /* Check if event is valid */ { /* Get state-matrix-element in dependency of current state and triggered event */ uint8_t i = ((uint8_t)self->current_state * self->num_events) + (uint8_t)self->event_occured; Fsm_StateElem_t stateEvaluation = self->transition_table_ptr[i]; self->current_state = stateEvaluation.next_state; /* Set new state */ self->internal_state = FSM_STATE_IDLE; /* Set internal state to \c IDLE */ retval = stateEvaluation.action_fptr; /* Return required action */ } else { self->internal_state = FSM_STATE_ERROR; /* Error occurred: Unknown event */ } self->event_occured = FSM_E_NILEVENT; /* Clear event variable */ } return retval; } /*! \brief Service function for Finite State Machines * \details The state machine will be serviced until it will be stopped by the user or no * further event is triggered. If a state transition occurred the associated action * will be executed. * \param self Instance pointer * \return Internal state of the state machine (see \ref Fsm_State_t). */ Fsm_State_t Fsm_Service(CFsm *self) { /* Internal state is set to \c FSM_STATE_SERVICE and any event is triggered? */ while((self->internal_state == FSM_STATE_SERVICE) && (self->event_occured != FSM_E_NILEVENT)) { Fsm_Act_t action_fptr = Fsm_StateEval(self); /* Execute state transition */ if(action_fptr != NULL) /* Action required ? */ { (*action_fptr)(self->inst_ptr); /* Execute action */ } } return self->internal_state; /* Return internal state machine state */ } /*! \brief Set an event * \details This function sets the given event and triggers the service for the given * state machine. * \param self Instance pointer * \param e New event */ void Fsm_SetEvent(CFsm *self, int8_t e) { if(self->internal_state != FSM_STATE_END) { self->event_occured = e; /* Set new event */ self->internal_state = FSM_STATE_SERVICE; /* Set internal state to \c FSM_STATE_SERVICE */ } } /*! \brief Sets the wait state * \details This function sets the given state state machine into the wait state. The state * machine stops and must be re-triggered. * \param self Instance pointer */ void Fsm_Wait(CFsm *self) { if(self->internal_state != FSM_STATE_END) { self->internal_state = FSM_STATE_WAIT; /* Set internal state to \c WAIT */ } } /*! \brief End processing of the state machine * \details If this function is called the given state machine will be stopped immediately. * \param self Instance pointer */ void Fsm_End(CFsm *self) { self->internal_state = FSM_STATE_END; /* Set internal state to \c END */ } /*! * @} * \endcond */ /*------------------------------------------------------------------------------------------------*/ /* End of file */ /*------------------------------------------------------------------------------------------------*/