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