summaryrefslogtreecommitdiffstats
path: root/ucs2-lib/src/ucs_fsm.c
blob: c180b0abc445964f1835a217804ba64bf4a6d883 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/*------------------------------------------------------------------------------------------------*/
/* 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 <http://www.gnu.org/licenses/>.                          */
/*                                                                                                */
/* 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                                                                                    */
/*------------------------------------------------------------------------------------------------*/