12fa3a6f89f223677bef533af255b3b51e744dc1
[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  */
92 bool determineStateWithHysteresis(SubStateIndex subStateIndex, TristateBoolean movingNow,
93                 MovementState * externalState) {
94         MovementState newState;
95         bool internalStateChange;
96         bool externalStateChange;
97         SubStateType * subState = &state.substate[subStateIndex];
98
99         (void) pthread_mutex_lock(&state.mutex);
100
101         /*
102          * Substate Internal State
103          */
104
105         if (movingNow == TRISTATE_BOOLEAN_SET) {
106                 newState = MOVEMENT_STATE_MOVING;
107         } else if (movingNow == TRISTATE_BOOLEAN_UNSET) {
108                 newState = MOVEMENT_STATE_STATIONARY;
109         } else {
110                 /* keep current sub-state */
111                 newState = subState->internalState;
112         }
113         internalStateChange = (subState->internalState != newState);
114         subState->internalState = newState;
115
116         /*
117          * Substate External State (+ hysteresis)
118          */
119
120         if (internalStateChange) {
121                 /* restart hysteresis for external state change when we have an internal
122                  * state change */
123                 subState->hysteresisCounter = 0;
124         }
125
126         /* when internal state and external state are not the same we need to
127          * perform hysteresis before we can propagate the internal state to the
128          * external state */
129         newState = subState->externalState;
130         if (subState->internalState != subState->externalState) {
131                 switch (subState->internalState) {
132                 case MOVEMENT_STATE_STATIONARY:
133                         /* internal state is STATIONARY, external state is MOVING */
134
135                         /* delay going to stationary a bit */
136                         subState->hysteresisCounter++;
137
138                         if (subState->hysteresisCounter >= subState->hysteresisCounterToStationary) {
139                                 /* outside the hysteresis range, go to stationary */
140                                 newState = MOVEMENT_STATE_STATIONARY;
141                         }
142                         break;
143
144                 case MOVEMENT_STATE_MOVING:
145                         /* internal state is MOVING, external state is STATIONARY */
146
147                         /* delay going to moving a bit */
148                         subState->hysteresisCounter++;
149
150                         if (subState->hysteresisCounter >= subState->hysteresisCounterToMoving) {
151                                 /* outside the hysteresis range, go to moving */
152                                 newState = MOVEMENT_STATE_MOVING;
153                         }
154                         break;
155
156                 default:
157                         /* when unknown then don't change state */
158                         break;
159                 }
160         }
161
162         externalStateChange = (subState->externalState != newState);
163         subState->externalState = newState;
164
165         /*
166          * external state may transition into MOVING when either one of the sub-states say so (OR), and
167          * may transition into STATIONARY when all of the sub-states say so (AND)
168          */
169         if (externalStateChange) {
170                 bool transition;
171
172                 if (newState == MOVEMENT_STATE_STATIONARY) {
173                         /* AND: all sub-states must agree on STATIONARY */
174                         int i = 0;
175
176                         transition = true;
177                         for (i = 0; i < SUBSTATE_COUNT; i++) {
178                                 transition = transition && (state.substate[i].externalState == newState);
179                         }
180                 } else /* if (newState == MOVEMENT_STATE_MOVING) */{
181                         /* OR: one sub-state wanting MOVING is enough */
182                         transition = true;
183                 }
184
185                 if (transition) {
186                         externalStateChange = (state.externalState != newState);
187                         state.externalState = newState;
188                 }
189         }
190
191
192         *externalState = state.externalState;
193
194         (void) pthread_mutex_unlock(&state.mutex);
195
196         return externalStateChange;
197 }
198
199 MovementState getInternalState(SubStateIndex subStateIndex) {
200         MovementState internalState;
201
202         (void) pthread_mutex_lock(&state.mutex);
203         internalState = state.substate[subStateIndex].internalState;
204         (void) pthread_mutex_unlock(&state.mutex);
205
206         return internalState;
207 }