c2bac6432e967f14464ee4ac0a98a4a80a4b93b0
[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         return state.externalState;
75 }
76
77 /**
78  * Determine new state
79  * @param subStateIndex
80  * the sub-state for/from which the new state should be determined
81  * @param movingNow
82  * the movement result of the sub-state
83  */bool determineStateWithHysteresis(SubStateIndex subStateIndex, TristateBoolean movingNow) {
84         MovementState newState;
85         bool internalStateChange;
86         bool externalStateChange;
87         SubStateType * subState = &state.substate[subStateIndex];
88
89         /*
90          * Substate Internal State
91          */
92
93         if (movingNow == TRISTATE_BOOLEAN_SET) {
94                 newState = MOVEMENT_STATE_MOVING;
95         } else if (movingNow == TRISTATE_BOOLEAN_UNSET) {
96                 newState = MOVEMENT_STATE_STATIONARY;
97         } else {
98                 /* keep current sub-state */
99                 newState = subState->internalState;
100         }
101         internalStateChange = (subState->internalState != newState);
102         subState->internalState = newState;
103
104         /*
105          * Substate External State (+ hysteresis)
106          */
107
108         if (internalStateChange) {
109                 /* restart hysteresis for external state change when we have an internal
110                  * state change */
111                 subState->hysteresisCounter = 0;
112         }
113
114         /* when internal state and external state are not the same we need to
115          * perform hysteresis before we can propagate the internal state to the
116          * external state */
117         newState = subState->externalState;
118         if (subState->internalState != subState->externalState) {
119                 switch (subState->internalState) {
120                 case MOVEMENT_STATE_STATIONARY:
121                         /* internal state is STATIONARY, external state is MOVING */
122
123                         /* delay going to stationary a bit */
124                         subState->hysteresisCounter++;
125
126                         if (subState->hysteresisCounter >= subState->hysteresisCounterToStationary) {
127                                 /* outside the hysteresis range, go to stationary */
128                                 newState = MOVEMENT_STATE_STATIONARY;
129                         }
130                         break;
131
132                 case MOVEMENT_STATE_MOVING:
133                         /* internal state is MOVING, external state is STATIONARY */
134
135                         /* delay going to moving a bit */
136                         subState->hysteresisCounter++;
137
138                         if (subState->hysteresisCounter >= subState->hysteresisCounterToMoving) {
139                                 /* outside the hysteresis range, go to moving */
140                                 newState = MOVEMENT_STATE_MOVING;
141                         }
142                         break;
143
144                 default:
145                         /* when unknown then don't change state */
146                         break;
147                 }
148         }
149
150         externalStateChange = (subState->externalState != newState);
151         subState->externalState = newState;
152
153         /*
154          * external state may transition into MOVING when either one of the sub-states say so (OR), and
155          * may transition into STATIONARY when all of the sub-states say so (AND)
156          */
157         if (externalStateChange) {
158                 bool transition;
159
160                 if (newState == MOVEMENT_STATE_STATIONARY) {
161                         /* AND: all sub-states must agree on STATIONARY */
162                         int i = 0;
163
164                         transition = true;
165                         for (i = 0; i < SUBSTATE_COUNT; i++) {
166                                 transition = transition && (state.substate[i].externalState == newState);
167                         }
168                 } else /* if (newState == MOVEMENT_STATE_MOVING) */{
169                         /* OR: one sub-state wanting MOVING is enough */
170                         transition = true;
171                 }
172
173                 if (transition) {
174                         externalStateChange = (state.externalState != newState);
175                         state.externalState = newState;
176                 }
177         }
178
179
180         return externalStateChange;
181 }
182
183 MovementState getInternalState(SubStateIndex subStateIndex) {
184         return state.substate[subStateIndex].internalState;
185 }