4 #include "configuration.h"
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 */
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 */
36 static StateType state;
42 bool initState(void) {
43 pthread_mutexattr_t attr;
44 if (pthread_mutexattr_init(&attr)) {
47 if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP)) {
50 if (pthread_mutex_init(&state.mutex, &attr)) {
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 */
69 void destroyState(void) {
70 (void) pthread_mutex_destroy(&state.mutex);
73 MovementState getExternalState(void) {
74 MovementState externalState;
76 (void) pthread_mutex_lock(&state.mutex);
77 externalState = state.externalState;
78 (void) pthread_mutex_unlock(&state.mutex);
85 * @param subStateIndex
86 * the sub-state for/from which the new state should be determined
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
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];
103 (void) pthread_mutex_lock(&state.mutex);
106 * Substate Internal State
109 if (movingNow == TRISTATE_BOOLEAN_SET) {
110 newState = MOVEMENT_STATE_MOVING;
111 } else if (movingNow == TRISTATE_BOOLEAN_UNSET) {
112 newState = MOVEMENT_STATE_STATIONARY;
114 /* keep current sub-state */
115 newState = subState->internalState;
117 internalStateChange = (subState->internalState != newState);
118 subState->internalState = newState;
121 * Substate External State (+ hysteresis)
124 if (internalStateChange) {
125 /* restart hysteresis for external state change when we have an internal
127 subState->hysteresisCounter = 0;
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
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 */
139 /* delay going to stationary a bit */
140 subState->hysteresisCounter++;
142 if (subState->hysteresisCounter >= subState->hysteresisCounterToStationary) {
143 /* outside the hysteresis range, go to stationary */
144 newState = MOVEMENT_STATE_STATIONARY;
148 case MOVEMENT_STATE_MOVING:
149 /* internal state is MOVING, external state is STATIONARY */
151 /* delay going to moving a bit */
152 subState->hysteresisCounter++;
154 if (subState->hysteresisCounter >= subState->hysteresisCounterToMoving) {
155 /* outside the hysteresis range, go to moving */
156 newState = MOVEMENT_STATE_MOVING;
161 /* when unknown then don't change state */
166 subStateExternalStateChanged = (subState->externalState != newState);
167 if (subStateExternalStateChange) {
168 *subStateExternalStateChange = subStateExternalStateChanged;
170 subState->externalState = newState;
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)
176 if (externalStateChange) {
177 *externalStateChange = false;
179 if (subStateExternalStateChanged) {
182 if (newState == MOVEMENT_STATE_STATIONARY) {
183 /* AND: all sub-states must agree on STATIONARY */
187 for (i = 0; i < SUBSTATE_COUNT; i++) {
188 transition = transition && (state.substate[i].externalState == newState);
190 } else /* if (newState == MOVEMENT_STATE_MOVING) */{
191 /* OR: one sub-state wanting MOVING is enough */
196 if (externalStateChange) {
197 *externalStateChange = (state.externalState != newState);
199 state.externalState = newState;
204 *externalState = state.externalState;
207 (void) pthread_mutex_unlock(&state.mutex);
210 MovementState getInternalState(SubStateIndex subStateIndex) {
211 MovementState internalState;
213 (void) pthread_mutex_lock(&state.mutex);
214 internalState = state.substate[subStateIndex].internalState;
215 (void) pthread_mutex_unlock(&state.mutex);
217 return internalState;