PUD: remove pointless mutex from state
[olsrd.git] / lib / pud / src / state.c
1 #include "state.h"
2
3 /* Plugin includes */
4 #include "configuration.h"
5
6 /* OLSRD includes */
7
8 /* System includes */
9
10 /*
11  * Types
12  */
13
14 /** Type describing substate */
15 typedef struct _SubStateType {
16         MovementState internalState; /**< the internal movement state */
17         unsigned long long hysteresisCounter; /**< the hysteresis counter */
18         unsigned long long hysteresisCounterToStationary; /**< the hysteresis counter threshold for changing the state to STATIONARY */
19         unsigned long long hysteresisCounterToMoving; /**< the hysteresis counter threshold for changing the state to MOVING */
20         MovementState externalState; /**< the externally visible movement state */
21 } SubStateType;
22
23 /** Type describing state */
24 typedef struct _StateType {
25         SubStateType substate[SUBSTATE_COUNT]; /**< the sub states */
26         MovementState externalState; /**< the externally visible movement state */
27 } StateType;
28
29 /*
30  * Variables
31  */
32
33 /** The state */
34 static StateType state;
35
36 /*
37  * Functions
38  */
39
40 void initState(void) {
41         state.substate[SUBSTATE_POSITION].internalState = MOVEMENT_STATE_STATIONARY;
42         state.substate[SUBSTATE_POSITION].hysteresisCounter = 0;
43         state.substate[SUBSTATE_POSITION].hysteresisCounterToStationary = getHysteresisCountToStationary();
44         state.substate[SUBSTATE_POSITION].hysteresisCounterToMoving = getHysteresisCountToMoving();
45         state.substate[SUBSTATE_POSITION].externalState = MOVEMENT_STATE_STATIONARY;
46         state.substate[SUBSTATE_GATEWAY].internalState = MOVEMENT_STATE_MOVING;
47         state.substate[SUBSTATE_GATEWAY].hysteresisCounter = 0;
48         state.substate[SUBSTATE_GATEWAY].hysteresisCounterToStationary = getGatewayHysteresisCountToStationary();
49         state.substate[SUBSTATE_GATEWAY].hysteresisCounterToMoving = getGatewayHysteresisCountToMoving();
50         state.substate[SUBSTATE_GATEWAY].externalState = MOVEMENT_STATE_MOVING;
51         state.externalState = MOVEMENT_STATE_MOVING; /* must comply to AND/OR conditions of sub-states */
52 }
53
54 MovementState getExternalState(void) {
55         return state.externalState;
56 }
57
58 /**
59  * Determine new state
60  * @param subStateIndex
61  * the sub-state for/from which the new state should be determined
62  * @param movingNow
63  * the movement result of the sub-state
64  * @param externalState
65  * a pointer to the variable in which to store the new external state
66  * @param externalStateChange
67  * a pointer to the variable in which to store whether the external state changed
68  * @param subStateExternalStateChange
69  * a pointer to the variable in which to store whether the sub-state external state changed
70  */
71 void determineStateWithHysteresis(SubStateIndex subStateIndex, TristateBoolean movingNow, MovementState * externalState,
72                 bool * externalStateChange, bool * subStateExternalStateChange) {
73         MovementState newState;
74         bool internalStateChange;
75         bool subStateExternalStateChanged;
76         SubStateType * subState = &state.substate[subStateIndex];
77
78         /*
79          * Substate Internal State
80          */
81
82         if (movingNow == TRISTATE_BOOLEAN_SET) {
83                 newState = MOVEMENT_STATE_MOVING;
84         } else if (movingNow == TRISTATE_BOOLEAN_UNSET) {
85                 newState = MOVEMENT_STATE_STATIONARY;
86         } else {
87                 /* keep current sub-state */
88                 newState = subState->internalState;
89         }
90         internalStateChange = (subState->internalState != newState);
91         subState->internalState = newState;
92
93         /*
94          * Substate External State (+ hysteresis)
95          */
96
97         if (internalStateChange) {
98                 /* restart hysteresis for external state change when we have an internal
99                  * state change */
100                 subState->hysteresisCounter = 0;
101         }
102
103         /* when internal state and external state are not the same we need to
104          * perform hysteresis before we can propagate the internal state to the
105          * external state */
106         newState = subState->externalState;
107         if (subState->internalState != subState->externalState) {
108                 switch (subState->internalState) {
109                 case MOVEMENT_STATE_STATIONARY:
110                         /* internal state is STATIONARY, external state is MOVING */
111
112                         /* delay going to stationary a bit */
113                         subState->hysteresisCounter++;
114
115                         if (subState->hysteresisCounter >= subState->hysteresisCounterToStationary) {
116                                 /* outside the hysteresis range, go to stationary */
117                                 newState = MOVEMENT_STATE_STATIONARY;
118                         }
119                         break;
120
121                 case MOVEMENT_STATE_MOVING:
122                         /* internal state is MOVING, external state is STATIONARY */
123
124                         /* delay going to moving a bit */
125                         subState->hysteresisCounter++;
126
127                         if (subState->hysteresisCounter >= subState->hysteresisCounterToMoving) {
128                                 /* outside the hysteresis range, go to moving */
129                                 newState = MOVEMENT_STATE_MOVING;
130                         }
131                         break;
132
133                 default:
134                         /* when unknown then don't change state */
135                         break;
136                 }
137         }
138
139         subStateExternalStateChanged = (subState->externalState != newState);
140         if (subStateExternalStateChange) {
141                 *subStateExternalStateChange = subStateExternalStateChanged;
142         }
143         subState->externalState = newState;
144
145         /*
146          * external state may transition into MOVING when either one of the sub-states say so (OR), and
147          * may transition into STATIONARY when all of the sub-states say so (AND)
148          */
149         if (externalStateChange) {
150                 *externalStateChange = false;
151         }
152         if (subStateExternalStateChanged) {
153                 bool transition;
154
155                 if (newState == MOVEMENT_STATE_STATIONARY) {
156                         /* AND: all sub-states must agree on STATIONARY */
157                         int i = 0;
158
159                         transition = true;
160                         for (i = 0; i < SUBSTATE_COUNT; i++) {
161                                 transition = transition && (state.substate[i].externalState == newState);
162                         }
163                 } else /* if (newState == MOVEMENT_STATE_MOVING) */{
164                         /* OR: one sub-state wanting MOVING is enough */
165                         transition = true;
166                 }
167
168                 if (transition) {
169                         if (externalStateChange) {
170                                 *externalStateChange = (state.externalState != newState);
171                         }
172                         state.externalState = newState;
173                 }
174         }
175
176         if (externalState) {
177                 *externalState = state.externalState;
178         }
179 }
180
181 MovementState getInternalState(SubStateIndex subStateIndex) {
182         return state.substate[subStateIndex].internalState;
183 }