amiro-os / core / src / aos_sssp.c @ c218345a
History | View | Annotate | Download (26.088 KB)
1 | cda14729 | Thomas Schöpping | /*
|
---|---|---|---|
2 | AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
|
||
3 | Copyright (C) 2016..2019 Thomas Schöpping et al.
|
||
4 | |||
5 | This program is free software: you can redistribute it and/or modify
|
||
6 | it under the terms of the GNU General Public License as published by
|
||
7 | the Free Software Foundation, either version 3 of the License, or
|
||
8 | (at your option) any later version.
|
||
9 | |||
10 | This program is distributed in the hope that it will be useful,
|
||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
13 | GNU General Public License for more details.
|
||
14 | |||
15 | You should have received a copy of the GNU General Public License
|
||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
17 | */
|
||
18 | |||
19 | /**
|
||
20 | * @file aos_sssp.c
|
||
21 | * @brief SSSP related code.
|
||
22 | *
|
||
23 | * @addtogroup aos_sssp
|
||
24 | * @{
|
||
25 | */
|
||
26 | |||
27 | #include <amiroos.h> |
||
28 | |||
29 | #if (AMIROOS_CFG_SSSP_ENABLE == true) || defined(__DOXYGEN__) |
||
30 | |||
31 | /******************************************************************************/
|
||
32 | /* LOCAL DEFINITIONS */
|
||
33 | /******************************************************************************/
|
||
34 | |||
35 | c218345a | Thomas Schöpping | #if ((AMIROOS_CFG_SSSP_MASTER != true) && (AMIROOS_CFG_PROFILE == true)) || defined(__DOXYGEN__) |
36 | |||
37 | /**
|
||
38 | * @brief Weighting factor for smoothing the @p _syncskew value.
|
||
39 | */
|
||
40 | #define SYNCSKEW_SMOOTHFACTOR (0.1f / AOS_SYSTEM_TIME_RESOLUTION) |
||
41 | |||
42 | #endif /* (AMIROOS_CFG_SSSP_MASTER != true) && (AMIROOS_CFG_PROFILE == true) */ |
||
43 | |||
44 | cda14729 | Thomas Schöpping | /******************************************************************************/
|
45 | /* EXPORTED VARIABLES */
|
||
46 | /******************************************************************************/
|
||
47 | |||
48 | /******************************************************************************/
|
||
49 | /* LOCAL TYPES */
|
||
50 | /******************************************************************************/
|
||
51 | |||
52 | /******************************************************************************/
|
||
53 | /* LOCAL VARIABLES */
|
||
54 | /******************************************************************************/
|
||
55 | |||
56 | /**
|
||
57 | c218345a | Thomas Schöpping | * @brief Pointer to the system uptime.
|
58 | */
|
||
59 | static aos_timestamp_t* _uptime;
|
||
60 | |||
61 | #if (AMIROOS_CFG_SSSP_MASTER == true) || defined(__DOXYGEN__) |
||
62 | |||
63 | /**
|
||
64 | * @brief Timer to drive the S signal for system wide time synchronization during operation phase.
|
||
65 | */
|
||
66 | static virtual_timer_t _synctimer;
|
||
67 | |||
68 | /**
|
||
69 | * @brief Last uptime of system wide time synchronization.
|
||
70 | */
|
||
71 | static aos_timestamp_t _synctime;
|
||
72 | |||
73 | #endif /* (AMIROOS_CFG_SSSP_MASTER == true) */ |
||
74 | |||
75 | #if ((AMIROOS_CFG_SSSP_MASTER != true) && (AMIROOS_CFG_PROFILE == true)) || defined(__DOXYGEN__) |
||
76 | |||
77 | /**
|
||
78 | * @brief Offset between local clock and system wide synchronization signal.
|
||
79 | */
|
||
80 | static float _syncskew; |
||
81 | |||
82 | #endif /* (AMIROOS_CFG_SSSP_MASTER != true) && (AMIROOS_CFG_PROFILE == true) */ |
||
83 | |||
84 | /**
|
||
85 | cda14729 | Thomas Schöpping | * @brief A timer event based delays.
|
86 | */
|
||
87 | static virtual_timer_t _delayTimer;
|
||
88 | |||
89 | /**
|
||
90 | * @brief Event source for the delay timer.
|
||
91 | */
|
||
92 | static event_source_t _eventSourceDelay;
|
||
93 | |||
94 | /**
|
||
95 | * @brief Event listener for the delay event.
|
||
96 | */
|
||
97 | static event_listener_t _eventListenerDelay;
|
||
98 | |||
99 | /******************************************************************************/
|
||
100 | /* LOCAL FUNCTIONS */
|
||
101 | /******************************************************************************/
|
||
102 | |||
103 | c218345a | Thomas Schöpping | #if (AMIROOS_CFG_SSSP_MASTER != true) || defined(__DOXYGEN__) |
104 | |||
105 | /**
|
||
106 | * @brief Callback function for the Sync signal interrupt.
|
||
107 | *
|
||
108 | * @param[in] args Pointer to the GPIO line identifier.
|
||
109 | */
|
||
110 | static void _gpioCallbackSSignal(void *args) |
||
111 | { |
||
112 | aosDbgCheck((args != NULL) && (*((ioline_t*)args) != PAL_NOLINE) && (PAL_PAD(*((ioline_t*)args)) < sizeof(eventflags_t) * 8)); |
||
113 | |||
114 | apalControlGpioState_t s; |
||
115 | aos_timestamp_t t; |
||
116 | |||
117 | chSysLockFromISR(); |
||
118 | |||
119 | // if the system is in operation phase
|
||
120 | if (aos.sssp.stage == AOS_SSSP_STAGE_OPERATION) {
|
||
121 | // read signal S
|
||
122 | apalControlGpioGet(&moduleSsspGpioS, &s); |
||
123 | // if S was toggled from on to off
|
||
124 | if (s == APAL_GPIO_OFF) {
|
||
125 | // get current uptime
|
||
126 | aosSysGetUptimeX(&t); |
||
127 | // align the uptime with the synchronization period
|
||
128 | t %= AMIROOS_CFG_SSSP_SYSSYNCPERIOD; |
||
129 | if (t < AMIROOS_CFG_SSSP_SYSSYNCPERIOD / 2) { |
||
130 | *_uptime -= t; |
||
131 | #if (AMIROOS_CFG_PROFILE == true) |
||
132 | _syncskew = ((1.0f - SYNCSKEW_SMOOTHFACTOR) * _syncskew) + (SYNCSKEW_SMOOTHFACTOR * t); |
||
133 | #endif /* (AMIROOS_CFG_PROFILE == true) */ |
||
134 | } else {
|
||
135 | t = AMIROOS_CFG_SSSP_SYSSYNCPERIOD - t; |
||
136 | *_uptime += t; |
||
137 | #if (AMIROOS_CFG_PROFILE == true) |
||
138 | _syncskew = ((1.0f - SYNCSKEW_SMOOTHFACTOR) * _syncskew) - (SYNCSKEW_SMOOTHFACTOR * t); |
||
139 | #endif /* (AMIROOS_CFG_PROFILE == true) */ |
||
140 | } |
||
141 | } |
||
142 | } |
||
143 | |||
144 | // broadcast event
|
||
145 | chEvtBroadcastFlagsI(&aos.events.gpio, AOS_GPIOEVENT_FLAG(PAL_PAD(*((ioline_t*)args)))); |
||
146 | chSysUnlockFromISR(); |
||
147 | |||
148 | return;
|
||
149 | } |
||
150 | |||
151 | #endif /* (AMIROOS_CFG_SSSP_MASTER != true) */ |
||
152 | |||
153 | #if (AMIROOS_CFG_SSSP_MASTER == true) || defined (__DOXYGEN__) |
||
154 | |||
155 | /**
|
||
156 | * @brief Periodic system synchronization callback function.
|
||
157 | * @details Toggles the SYS_SYNC signal and reconfigures the system synchronization timer.
|
||
158 | *
|
||
159 | * @param[in] par Unused parameters.
|
||
160 | */
|
||
161 | static void _syncTimerCallback(void* par) |
||
162 | { |
||
163 | (void)par;
|
||
164 | |||
165 | apalControlGpioState_t state; |
||
166 | aos_timestamp_t uptime; |
||
167 | |||
168 | chSysLockFromISR(); |
||
169 | // toggle and read signal S
|
||
170 | apalGpioToggle(moduleSsspGpioS.gpio); |
||
171 | apalControlGpioGet(&moduleSsspGpioS, &state); |
||
172 | // if S was toggled from off to on
|
||
173 | if (state == APAL_GPIO_ON) {
|
||
174 | // reconfigure the timer precisely, because the logically falling edge (next interrupt) snychronizes the system time
|
||
175 | _synctime += AMIROOS_CFG_SSSP_SYSSYNCPERIOD; |
||
176 | aosSysGetUptimeX(&uptime); |
||
177 | chVTSetI(&_synctimer, chTimeUS2I(_synctime - uptime), _syncTimerCallback, NULL);
|
||
178 | } |
||
179 | // if S was toggled from on to off
|
||
180 | else /* if (state == APAL_GPIO_OFF) */ { |
||
181 | // reconfigure the timer (lazy)
|
||
182 | chVTSetI(&_synctimer, chTimeUS2I(AMIROOS_CFG_SSSP_SYSSYNCPERIOD / 2), _syncTimerCallback, NULL); |
||
183 | } |
||
184 | chSysUnlockFromISR(); |
||
185 | |||
186 | return;
|
||
187 | } |
||
188 | |||
189 | /**
|
||
190 | * @brief Start the timer that toggles S for synchronization of the system.
|
||
191 | * @note Must be called from a locked context.
|
||
192 | */
|
||
193 | static inline void _syncTimerStartS(void) |
||
194 | { |
||
195 | chDbgCheckClassS(); |
||
196 | |||
197 | // start synchronization timer
|
||
198 | // The first iteration of the timer is set to the next 'center' of a 'slice'.
|
||
199 | aos_timestamp_t t; |
||
200 | aosSysGetUptimeX(&t); |
||
201 | t = AMIROOS_CFG_SSSP_SYSSYNCPERIOD - (t % AMIROOS_CFG_SSSP_SYSSYNCPERIOD); |
||
202 | chVTSetI(&_synctimer, chTimeUS2I((t > (AMIROOS_CFG_SSSP_SYSSYNCPERIOD / 2)) ? (t - (AMIROOS_CFG_SSSP_SYSSYNCPERIOD / 2)) : (t + (AMIROOS_CFG_SSSP_SYSSYNCPERIOD / 2))), _syncTimerCallback, NULL); |
||
203 | |||
204 | return;
|
||
205 | } |
||
206 | |||
207 | #endif /* (AMIROOS_CFG_SSSP_MASTER == true) */ |
||
208 | |||
209 | cda14729 | Thomas Schöpping | /**
|
210 | * @brief General callback function to be used for any local timers.
|
||
211 | *
|
||
212 | * @param[in] par A pointer to an @p event_source_t to be fired.
|
||
213 | */
|
||
214 | static void _timerCallback(void* par) |
||
215 | { |
||
216 | aosDbgCheck(par != NULL);
|
||
217 | |||
218 | chSysLockFromISR(); |
||
219 | chEvtBroadcastI((event_source_t*)par); |
||
220 | chSysUnlockFromISR(); |
||
221 | |||
222 | return;
|
||
223 | } |
||
224 | |||
225 | /**
|
||
226 | * @brief Waits for the S signal to switch to the desired state.
|
||
227 | *
|
||
228 | * @param[in] listener Pointer to the GPIO event listener to be used.
|
||
229 | * @param[in] flags Event flags to listen to by the event listener (indicating a S signal event).
|
||
230 | * @param[in] signalstate Desired state of the S signal ti be waited for.
|
||
231 | * @param[out] received Output variable to store the received event mask to.
|
||
232 | *
|
||
233 | * @return Status, indicating whether the expected event was received.
|
||
234 | */
|
||
235 | static inline aos_status_t _waitForS(event_listener_t* listener, eventflags_t flags, apalControlGpioState_t signalstate, eventmask_t* received) |
||
236 | { |
||
237 | aosDbgCheck(listener != NULL);
|
||
238 | aosDbgCheck(flags != 0);
|
||
239 | aosDbgCheck(received != NULL);
|
||
240 | |||
241 | // wait for the next event (do not apply any filters in order not to miss any events)
|
||
242 | *received = chEvtWaitOne(ALL_EVENTS); |
||
243 | // if the correct event was triggered
|
||
244 | if (*received == listener->events) {
|
||
245 | apalControlGpioState_t s; |
||
246 | apalControlGpioGet(&moduleSsspGpioS, &s); |
||
247 | // only check for the expected event
|
||
248 | if (flags & listener->flags && s == signalstate) {
|
||
249 | // unset the expected flags but keep any other ones
|
||
250 | listener->flags &= ~flags; |
||
251 | return AOS_SUCCESS;
|
||
252 | } |
||
253 | } |
||
254 | |||
255 | return AOS_FAILURE;
|
||
256 | } |
||
257 | |||
258 | /**
|
||
259 | * @brief Uses the local delay timer to setup a timed event and waits for it to fire.
|
||
260 | *
|
||
261 | * @param[in] dt Delay time in microseconds to be set to the timer.
|
||
262 | * @param[in] mask Event mask to be used for the delay timer.
|
||
263 | * @param[in] arm_timer Flag to indicate whether the timer has to be armed yet (i.e. on first call of this function).
|
||
264 | * @param[out] received Output variable to store the received event mask to.
|
||
265 | *
|
||
266 | * @return Status, indicating whether the expected event (delay timer) was received.
|
||
267 | */
|
||
268 | static inline aos_status_t _delay(uint32_t dt, eventmask_t mask, bool arm_timer, eventmask_t* received) |
||
269 | { |
||
270 | aosDbgCheck(dt != TIME_IMMEDIATE); |
||
271 | aosDbgCheck(mask != 0);
|
||
272 | aosDbgCheck(received != NULL);
|
||
273 | |||
274 | // arm the delay timer once
|
||
275 | if (arm_timer) {
|
||
276 | chEvtRegisterMask(&_eventSourceDelay, &_eventListenerDelay, mask); |
||
277 | chVTSet(&_delayTimer, chTimeUS2I(dt), _timerCallback, &_eventSourceDelay); |
||
278 | } |
||
279 | |||
280 | // wait for any event to occur (do not apply any filters in order not to miss any events)
|
||
281 | *received = chEvtWaitOne(ALL_EVENTS); |
||
282 | |||
283 | // if the timer event was received, cleanup
|
||
284 | if (*received & _eventListenerDelay.events) {
|
||
285 | chEvtUnregister(&_eventSourceDelay, &_eventListenerDelay); |
||
286 | return AOS_SUCCESS;
|
||
287 | } |
||
288 | |||
289 | return AOS_FAILURE;
|
||
290 | } |
||
291 | |||
292 | /******************************************************************************/
|
||
293 | /* EXPORTED FUNCTIONS */
|
||
294 | /******************************************************************************/
|
||
295 | |||
296 | /**
|
||
297 | * @brief Initialize all SSSP related data.
|
||
298 | */
|
||
299 | c218345a | Thomas Schöpping | void aosSsspInit(aos_timestamp_t* system_uptime)
|
300 | cda14729 | Thomas Schöpping | { |
301 | c218345a | Thomas Schöpping | aosDbgCheck(system_uptime != NULL);
|
302 | |||
303 | 510b93cc | Thomas Schöpping | // local variables
|
304 | apalControlGpioState_t state; |
||
305 | cda14729 | Thomas Schöpping | |
306 | #if (AMIROOS_CFG_SSSP_STARTUP == true) |
||
307 | // AMiRo-OS has to perform the basic initialization
|
||
308 | aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_1_1; |
||
309 | #else /* (AMIROOS_CFG_SSSP_STARTUP == true) */ |
||
310 | // basic initialization was already performed by a bootloader
|
||
311 | aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_2_1; |
||
312 | #endif /* (AMIROOS_CFG_SSSP_STARTUP == true) */ |
||
313 | |||
314 | 510b93cc | Thomas Schöpping | // check all SSSP signals for correct state
|
315 | apalControlGpioGet(&moduleSsspGpioS, &state); |
||
316 | aosDbgAssert(state == APAL_GPIO_ON); |
||
317 | apalControlGpioGet(&moduleSsspGpioPD, &state); |
||
318 | aosDbgAssert(state == APAL_GPIO_OFF); |
||
319 | c218345a | Thomas Schöpping | #if (AMIROOS_CFG_SSSP_MSI == true) |
320 | 510b93cc | Thomas Schöpping | #if (AMIROOS_CFG_SSSP_STACK_END != true) |
321 | apalControlGpioGet(&moduleSsspGpioUP, &state); |
||
322 | aosDbgAssert(state == APAL_GPIO_OFF); |
||
323 | #endif /* (AMIROOS_CFG_SSSP_STACK_END != true) */ |
||
324 | #if (AMIROOS_CFG_SSSP_STACK_START != true) |
||
325 | apalControlGpioGet(&moduleSsspGpioDN, &state); |
||
326 | aosDbgAssert(state == APAL_GPIO_OFF); |
||
327 | #endif /* (AMIROOS_CFG_SSSP_STACK_START != true) */ |
||
328 | c218345a | Thomas Schöpping | #endif /* (AMIROOS_CFG_SSSP_MSI == true) */ |
329 | 510b93cc | Thomas Schöpping | |
330 | #if (AMIROOS_CFG_SSSP_MSI == true) |
||
331 | // module ID is initialized as 'invalid'
|
||
332 | aos.sssp.moduleId = AOS_SSSP_MODULEID_INVALID; |
||
333 | #endif /* (AMIROOS_CFG_SSSP_MSI == true) */ |
||
334 | |||
335 | cda14729 | Thomas Schöpping | // initialize static variables
|
336 | c218345a | Thomas Schöpping | _uptime = system_uptime; |
337 | #if (AMIROOS_CFG_SSSP_MASTER == true) |
||
338 | chVTObjectInit(&_synctimer); |
||
339 | _synctime = 0;
|
||
340 | #endif /* (AMIROOS_CFG_SSSP_MASTER == true) */ |
||
341 | #if (AMIROOS_CFG_SSSP_MASTER != true) && (AMIROOS_CFG_PROFILE == true) |
||
342 | _syncskew = 0.0f; |
||
343 | #endif /* (AMIROOS_CFG_SSSP_MASTER != true) && (AMIROOS_CFG_PROFILE == true) */ |
||
344 | cda14729 | Thomas Schöpping | chVTObjectInit(&_delayTimer); |
345 | chEvtObjectInit(&_eventSourceDelay); |
||
346 | |||
347 | c218345a | Thomas Schöpping | // signal interrupt setup
|
348 | palSetLineCallback(moduleSsspGpioPD.gpio->line, aosSysGetStdGpioCallback(), &moduleSsspGpioPD.gpio->line); |
||
349 | palEnableLineEvent(moduleSsspGpioPD.gpio->line, APAL2CH_EDGE(moduleSsspGpioPD.meta.edge)); |
||
350 | #if (AMIROOS_CFG_SSSP_MASTER == true) |
||
351 | palSetLineCallback(moduleSsspGpioS.gpio->line, aosSysGetStdGpioCallback(), &moduleSsspGpioS.gpio->line); |
||
352 | #else /* (AMIROOS_CFG_SSSP_MASTER == true) */ |
||
353 | palSetLineCallback(moduleSsspGpioS.gpio->line, _gpioCallbackSSignal, &moduleSsspGpioS.gpio->line); |
||
354 | #endif /* (AMIROOS_CFG_SSSP_MASTER == true) */ |
||
355 | palEnableLineEvent(moduleSsspGpioS.gpio->line, APAL2CH_EDGE(moduleSsspGpioS.meta.edge)); |
||
356 | #if (AMIROOS_CFG_SSSP_MSI == true) |
||
357 | #if (AMIROOS_CFG_SSSP_STACK_START != true) |
||
358 | palSetLineCallback(moduleSsspGpioDN.gpio->line, aosSysGetStdGpioCallback(), &moduleSsspGpioDN.gpio->line); |
||
359 | palEnableLineEvent(moduleSsspGpioDN.gpio->line, APAL2CH_EDGE(moduleSsspGpioDN.meta.edge)); |
||
360 | #endif /* (AMIROOS_CFG_SSSP_STACK_START != true) */ |
||
361 | #if (AMIROOS_CFG_SSSP_STACK_END != true) |
||
362 | palSetLineCallback(moduleSsspGpioUP.gpio->line, aosSysGetStdGpioCallback(), &moduleSsspGpioUP.gpio->line); |
||
363 | palEnableLineEvent(moduleSsspGpioUP.gpio->line, APAL2CH_EDGE(moduleSsspGpioUP.meta.edge)); |
||
364 | #endif /* (AMIROOS_CFG_SSSP_STACK_END != true) */ |
||
365 | #endif /* (AMIROOS_CFG_SSSP_MSI == true) */ |
||
366 | |||
367 | cda14729 | Thomas Schöpping | return;
|
368 | } |
||
369 | |||
370 | /**
|
||
371 | * @brief Proceed to the next SSSP stage.
|
||
372 | c218345a | Thomas Schöpping | * @note Calling this function when in operation phase is invalid.
|
373 | * The function aosSsspShutdownInit() must be used instead.
|
||
374 | cda14729 | Thomas Schöpping | *
|
375 | * @param[in] listener An optional listener, in case the system has to wait for a specific event.
|
||
376 | * @param[in] flags The relevant flags to wait for (mandatory if a listener is given).
|
||
377 | * @param[in] mask If the stage transition involves a timer event (handled internally by this function),
|
||
378 | * the given input value of this parameter defines the mask to be used for that event.
|
||
379 | * In case a listener was specified, the according mask is retrieved from the listener but this parameter is still used as input for sanity checks.
|
||
380 | * @param[out] received Output variable to store the received event mask to.
|
||
381 | *
|
||
382 | * @return Status, indicating whether proceeding in the protocol was successful.
|
||
383 | */
|
||
384 | aos_status_t aosSsspProceed(event_listener_t* listener, eventflags_t flags, eventmask_t mask, eventmask_t* received) |
||
385 | { |
||
386 | // local variables
|
||
387 | #pragma GCC diagnostic push
|
||
388 | #pragma GCC diagnostic ignored "-Wunused-but-set-variable" |
||
389 | static aos_ssspstage_t laststage = AOS_SSSP_STAGE_UNDEFINED;
|
||
390 | #pragma GCC diagnostic pop
|
||
391 | aos_ssspstage_t nextstage = aos.sssp.stage; |
||
392 | |||
393 | // behaviour depends on current SSSP stage of the system
|
||
394 | switch (aos.sssp.stage) {
|
||
395 | #if (AMIROOS_CFG_SSSP_STARTUP == true) |
||
396 | |||
397 | /*
|
||
398 | * Deactivate S signal.
|
||
399 | * Master node delays execution by one period AOS_SSSP_DELAY.
|
||
400 | */
|
||
401 | case AOS_SSSP_STAGE_STARTUP_1_1:
|
||
402 | { |
||
403 | #if (AMIROOS_CFG_SSSP_MASTER == true) |
||
404 | aosDbgCheck(listener == NULL);
|
||
405 | aosDbgCheck(flags == 0);
|
||
406 | aosDbgCheck(mask != 0);
|
||
407 | aosDbgCheck(received != NULL);
|
||
408 | |||
409 | // delay execution and deactivate the S signal on success
|
||
410 | if (_delay(AOS_SSSP_DELAY, mask, (laststage != AOS_SSSP_STAGE_STARTUP_1_1), received) == AOS_SUCCESS) {
|
||
411 | apalControlGpioSet(&moduleSsspGpioS, APAL_GPIO_OFF); |
||
412 | nextstage = AOS_SSSP_STAGE_STARTUP_1_2; |
||
413 | } |
||
414 | #else /* (AMIROOS_CFG_SSSP_MASTER == true) */ |
||
415 | aosDbgCheck(listener == NULL);
|
||
416 | aosDbgCheck(flags == 0);
|
||
417 | aosDbgCheck(mask == 0);
|
||
418 | aosDbgCheck(received == NULL);
|
||
419 | |||
420 | // deactivate S signal and proceed
|
||
421 | apalControlGpioSet(&moduleSsspGpioS, APAL_GPIO_OFF); |
||
422 | nextstage = AOS_SSSP_STAGE_STARTUP_1_2; |
||
423 | #endif /* (AMIROOS_CFG_SSSP_MASTER == true) */ |
||
424 | break;
|
||
425 | } |
||
426 | |||
427 | /*
|
||
428 | * Wait for the S signal to become inactive.
|
||
429 | */
|
||
430 | case AOS_SSSP_STAGE_STARTUP_1_2:
|
||
431 | { |
||
432 | aosDbgCheck(listener != NULL);
|
||
433 | aosDbgCheck(flags != 0);
|
||
434 | aosDbgCheck(mask == listener->events); |
||
435 | aosDbgCheck(received != NULL);
|
||
436 | |||
437 | // wait for the S signal to become inactive and proceed on success
|
||
438 | if (_waitForS(listener, flags, APAL_GPIO_OFF, received) == AOS_SUCCESS) {
|
||
439 | nextstage = AOS_SSSP_STAGE_STARTUP_1_3; |
||
440 | } |
||
441 | break;
|
||
442 | } |
||
443 | |||
444 | /*
|
||
445 | * Wait for the S signal to be activated by the master module.
|
||
446 | * The master delays execution by one period AOS_SSSP_DELAY.
|
||
447 | */
|
||
448 | case AOS_SSSP_STAGE_STARTUP_1_3:
|
||
449 | { |
||
450 | #if (AMIROOS_CFG_SSSP_MASTER == true) |
||
451 | aosDbgCheck(listener == NULL);
|
||
452 | aosDbgCheck(flags == 0);
|
||
453 | aosDbgCheck(mask != 0);
|
||
454 | aosDbgCheck(received != NULL);
|
||
455 | |||
456 | // delay execution and deactivate the S signal on success
|
||
457 | if (_delay(AOS_SSSP_DELAY, mask, (laststage != AOS_SSSP_STAGE_STARTUP_1_3), received) == AOS_SUCCESS) {
|
||
458 | apalControlGpioSet(&moduleSsspGpioS, APAL_GPIO_ON); |
||
459 | nextstage = AOS_SSSP_STAGE_STARTUP_2_1; |
||
460 | } |
||
461 | #else /* (AMIROOS_CFG_SSSP_MASTER == true) */ |
||
462 | aosDbgCheck(listener != NULL);
|
||
463 | aosDbgCheck(flags != 0);
|
||
464 | aosDbgCheck(mask == listener->events); |
||
465 | aosDbgCheck(received != NULL);
|
||
466 | |||
467 | // wait for the S signal to become active and activate it as well and proceed on success
|
||
468 | if (_waitForS(listener, flags, APAL_GPIO_ON, received) == AOS_SUCCESS) {
|
||
469 | apalControlGpioSet(&moduleSsspGpioS, APAL_GPIO_ON); |
||
470 | nextstage = AOS_SSSP_STAGE_STARTUP_2_1; |
||
471 | } |
||
472 | #endif /* (AMIROOS_CFG_SSSP_MASTER == true) */ |
||
473 | break;
|
||
474 | } |
||
475 | |||
476 | #endif /* (AMIROOS_CFG_SSSP_STARTUP == true) */ |
||
477 | |||
478 | /*
|
||
479 | * Deactivate S signal.
|
||
480 | * Master node delays execution by one period AOS_SSSP_DELAY
|
||
481 | */
|
||
482 | case AOS_SSSP_STAGE_STARTUP_2_1:
|
||
483 | { |
||
484 | #if (AMIROOS_CFG_SSSP_MASTER == true) |
||
485 | aosDbgCheck(listener == NULL);
|
||
486 | aosDbgCheck(flags == 0);
|
||
487 | aosDbgCheck(mask != 0);
|
||
488 | aosDbgCheck(received != NULL);
|
||
489 | |||
490 | // delay execution and deactivate the S signal on success
|
||
491 | if (_delay(AOS_SSSP_DELAY, mask, (laststage != AOS_SSSP_STAGE_STARTUP_2_1), received) == AOS_SUCCESS) {
|
||
492 | apalControlGpioSet(&moduleSsspGpioS, APAL_GPIO_OFF); |
||
493 | nextstage = AOS_SSSP_STAGE_STARTUP_2_2; |
||
494 | } |
||
495 | #else /* (AMIROOS_CFG_SSSP_MASTER == true) */ |
||
496 | aosDbgCheck(listener == NULL);
|
||
497 | aosDbgCheck(flags == 0);
|
||
498 | aosDbgCheck(mask == 0);
|
||
499 | aosDbgCheck(received == NULL);
|
||
500 | |||
501 | // deactivate S signal and proceed
|
||
502 | apalControlGpioSet(&moduleSsspGpioS, APAL_GPIO_OFF); |
||
503 | nextstage = AOS_SSSP_STAGE_STARTUP_2_2; |
||
504 | mask = 0;
|
||
505 | #endif /* (AMIROOS_CFG_SSSP_MASTER == true) */ |
||
506 | break;
|
||
507 | } |
||
508 | |||
509 | /*
|
||
510 | * Wait for the S signal to become inactive.
|
||
511 | c218345a | Thomas Schöpping | * When proceeding to operation phase, the master starts toggling S for synchronization
|
512 | cda14729 | Thomas Schöpping | */
|
513 | case AOS_SSSP_STAGE_STARTUP_2_2:
|
||
514 | { |
||
515 | aosDbgCheck(listener != NULL);
|
||
516 | aosDbgCheck(flags != 0);
|
||
517 | aosDbgCheck(mask == listener->events); |
||
518 | aosDbgCheck(received != NULL);
|
||
519 | |||
520 | // wait for the S signal to become inactive and proceed on success
|
||
521 | if (_waitForS(listener, flags, APAL_GPIO_OFF, received) == AOS_SUCCESS) {
|
||
522 | #if (AMIROOS_CFG_SSSP_MSI == true) |
||
523 | nextstage = AOS_SSSP_STAGE_STARTUP_3; |
||
524 | #else /* (AMIROOS_CFG_SSSP_MSI == true) */ |
||
525 | c218345a | Thomas Schöpping | chSysLock(); |
526 | // start the internal uptime aggregation
|
||
527 | aosSysStartUptimeS(); |
||
528 | #if (AMIROOS_CFG_SSSP_MASTER == true) |
||
529 | // start toggling S for system synchronization
|
||
530 | _syncTimerStartS(); |
||
531 | #endif /* (AMIROOS_CFG_SSSP_MASTER == true) */ |
||
532 | chSysUnlock(); |
||
533 | cda14729 | Thomas Schöpping | nextstage = AOS_SSSP_STAGE_OPERATION; |
534 | #endif /* (AMIROOS_CFG_SSSP_MSI == true) */ |
||
535 | } |
||
536 | break;
|
||
537 | } |
||
538 | |||
539 | #if (AMIROOS_CFG_SSSP_MSI == true) |
||
540 | |||
541 | //TODO
|
||
542 | |||
543 | #endif /* (AMIROOS_CFG_SSSP_MSI == true) */ |
||
544 | |||
545 | /*
|
||
546 | c218345a | Thomas Schöpping | * Invalid operation.
|
547 | * Shutdon must be initiatid via the aosSsspShutdownInit() function.
|
||
548 | */
|
||
549 | case AOS_SSSP_STAGE_OPERATION:
|
||
550 | { |
||
551 | aosDbgAssertMsg(false, "in order to exit operation phase, aosSsspShutdownInit() function must be used"); |
||
552 | break;
|
||
553 | } |
||
554 | |||
555 | /*
|
||
556 | cda14729 | Thomas Schöpping | * Delay execution by one perion AOS_SSSP_DELAY, deactivate the SYNC signal and proceed.
|
557 | * NOTE: Actually only the module that initiated the shutdown has to delay execution here.
|
||
558 | * For the sake of simlicity though, each module delays execution.
|
||
559 | */
|
||
560 | case AOS_SSSP_STAGE_SHUTDOWN_1_2:
|
||
561 | { |
||
562 | aosDbgCheck(listener == NULL);
|
||
563 | aosDbgCheck(flags == 0);
|
||
564 | aosDbgCheck(mask == 0);
|
||
565 | aosDbgCheck(received == NULL);
|
||
566 | |||
567 | // delay execution
|
||
568 | aosThdUSleep(AOS_SSSP_DELAY); |
||
569 | // deactivate S signal
|
||
570 | apalControlGpioSet(&moduleSsspGpioS, APAL_GPIO_OFF); |
||
571 | nextstage = AOS_SSSP_STAGE_SHUTDOWN_1_3; |
||
572 | break;
|
||
573 | } |
||
574 | |||
575 | #if (AMIROOS_CFG_SSSP_SHUTDOWN == true) |
||
576 | |||
577 | /*
|
||
578 | * Wait for S signal to become inactive.
|
||
579 | */
|
||
580 | case AOS_SSSP_STAGE_SHUTDOWN_1_3:
|
||
581 | { |
||
582 | aosDbgCheck(listener != NULL);
|
||
583 | aosDbgCheck(flags != 0);
|
||
584 | aosDbgCheck(mask == listener->events); |
||
585 | aosDbgCheck(received != NULL);
|
||
586 | |||
587 | // wait for the S signal to become inactive and proceed on success
|
||
588 | if (_waitForS(listener, flags, APAL_GPIO_OFF, received) == AOS_SUCCESS) {
|
||
589 | nextstage = AOS_SSSP_STAGE_SHUTDOWN_2_1; |
||
590 | } |
||
591 | break;
|
||
592 | } |
||
593 | |||
594 | /*
|
||
595 | * Evaluate PD signal to determine whether a shutdown or restart is requested.
|
||
596 | * The logical state is returned by the function call.
|
||
597 | */
|
||
598 | case AOS_SSSP_STAGE_SHUTDOWN_2_1:
|
||
599 | { |
||
600 | aosDbgCheck(listener == NULL);
|
||
601 | aosDbgCheck(flags == 0);
|
||
602 | aosDbgCheck(mask == 0);
|
||
603 | aosDbgCheck(received != NULL);
|
||
604 | |||
605 | // evaluate PD signal
|
||
606 | apalControlGpioState_t pd; |
||
607 | apalControlGpioGet(&moduleSsspGpioPD, &pd); |
||
608 | *received = (pd == APAL_GPIO_ON) ? (eventmask_t)~0 : 0; |
||
609 | nextstage = AOS_SSSP_STAGE_SHUTDOWN_2_2; |
||
610 | break;
|
||
611 | } |
||
612 | |||
613 | /*
|
||
614 | * Proceed with no further actions required.
|
||
615 | */
|
||
616 | case AOS_SSSP_STAGE_SHUTDOWN_2_2:
|
||
617 | { |
||
618 | aosDbgCheck(listener == NULL);
|
||
619 | aosDbgCheck(flags == 0);
|
||
620 | aosDbgCheck(mask == 0);
|
||
621 | aosDbgCheck(received == NULL);
|
||
622 | |||
623 | nextstage = AOS_SSSP_STAGE_SHUTDOWN_2_3; |
||
624 | break;
|
||
625 | } |
||
626 | |||
627 | #endif /* (AMIROOS_CFG_SSSP_SHUTDOWN == true) */ |
||
628 | |||
629 | default:
|
||
630 | { |
||
631 | // this case must never occur!
|
||
632 | aosDbgAssertMsg(false, "Invalid SSSP stage tranition occurred"); |
||
633 | break;
|
||
634 | } |
||
635 | } /* end of switch (aos.sssp.stage) */
|
||
636 | |||
637 | // outro and return
|
||
638 | laststage = aos.sssp.stage; |
||
639 | const aos_status_t status = (nextstage > aos.sssp.stage) ? AOS_SUCCESS : AOS_FAILURE;
|
||
640 | aos.sssp.stage = nextstage; |
||
641 | |||
642 | return status;
|
||
643 | } |
||
644 | |||
645 | c218345a | Thomas Schöpping | /**
|
646 | * @brief Leave the operation pahse and initiate or acknowledge shutdown.
|
||
647 | *
|
||
648 | * @param[in] active Flag, indicating whether the shutdon shall be activeliy initiated (true) or a passive request was received (false).
|
||
649 | */
|
||
650 | void aosSsspShutdownInit(bool active) |
||
651 | cda14729 | Thomas Schöpping | { |
652 | c218345a | Thomas Schöpping | aosDbgAssert(aos.sssp.stage == AOS_SSSP_STAGE_OPERATION); |
653 | |||
654 | cda14729 | Thomas Schöpping | // proceed to shutdown phase
|
655 | c218345a | Thomas Schöpping | aos.sssp.stage = AOS_SSSP_STAGE_SHUTDOWN_1_1; |
656 | |||
657 | // activate PD if this was an active shutdown initiation
|
||
658 | if (active) {
|
||
659 | apalControlGpioSet(&moduleSsspGpioPD, APAL_GPIO_ON); |
||
660 | } |
||
661 | |||
662 | #if (AMIROOS_CFG_SSSP_MASTER == true) |
||
663 | // stop toggling S
|
||
664 | chVTReset(&_synctimer); |
||
665 | #endif /* (AMIROOS_CFG_SSSP_MASTER == true) */ |
||
666 | |||
667 | // activate S
|
||
668 | apalControlGpioSet(&moduleSsspGpioS, APAL_GPIO_ON); |
||
669 | |||
670 | // proceed in the shutdown phase
|
||
671 | cda14729 | Thomas Schöpping | aos.sssp.stage = AOS_SSSP_STAGE_SHUTDOWN_1_2; |
672 | |||
673 | return;
|
||
674 | } |
||
675 | |||
676 | #if (AMIROOS_CFG_SSSP_SHUTDOWN == true) || defined(__DOXYGEN__) |
||
677 | |||
678 | /**
|
||
679 | * @brief Sequnetially broadcast an identifier via S to specify a specific way to shutdown or restart.
|
||
680 | *
|
||
681 | * @param[in] identifier Identifier to be broadcasted.
|
||
682 | */
|
||
683 | void aosSsspShutdownBroadcastIdentifier(unsigned int identifier) |
||
684 | { |
||
685 | // only broadcast anything if a identifier greater than 0 was specified
|
||
686 | if (identifier > 0) { |
||
687 | // broadcast identifier
|
||
688 | for (unsigned int pulse = 0; pulse < identifier; ++pulse) { |
||
689 | // wait one delay time with S being deactivated
|
||
690 | aosThdUSleep(AOS_SSSP_DELAY); |
||
691 | |||
692 | // activate S for one AOS_SSSP_DELAY.
|
||
693 | apalControlGpioSet(&moduleSsspGpioS, APAL_GPIO_ON); |
||
694 | aosThdUSleep(AOS_SSSP_DELAY); |
||
695 | apalControlGpioSet(&moduleSsspGpioS, APAL_GPIO_OFF); |
||
696 | } |
||
697 | } |
||
698 | |||
699 | // let a timeout pass and return
|
||
700 | aosThdUSleep(AOS_SSSP_TIMEOUT); |
||
701 | |||
702 | return;
|
||
703 | } |
||
704 | |||
705 | /**
|
||
706 | * @brief Wait for a pulse during the SSSP shutdown disambiguation procedure.
|
||
707 | * @details Whenever a pulse is received, the identifier is incremented.
|
||
708 | * Otherwise the internal timer is configured and will eventually trigger a timeout event.
|
||
709 | *
|
||
710 | * @param[in] gpiolistener Event listener for GPIO events.
|
||
711 | * @param[in] sflags Event flags to be set by edges on the S signal.
|
||
712 | * @param[in] timermask Event maks to use for the internal timer.
|
||
713 | * @param[in,out] identifier Identifier variable to increment.
|
||
714 | *
|
||
715 | * @return The event mask of whatever event was received during this function call.
|
||
716 | */
|
||
717 | eventmask_t aosSsspShutdownWaitForIdentifierPulse(event_listener_t* gpiolistener, const eventflags_t sflags, eventmask_t timermask, unsigned int* identifier) |
||
718 | { |
||
719 | aosDbgCheck(gpiolistener != NULL);
|
||
720 | aosDbgCheck(sflags != 0);
|
||
721 | aosDbgCheck(timermask != 0);
|
||
722 | aosDbgCheck(identifier != NULL);
|
||
723 | |||
724 | // local variables
|
||
725 | eventmask_t mask; |
||
726 | eventflags_t flags; |
||
727 | apalControlGpioState_t sstate; |
||
728 | |||
729 | // arm the timer once
|
||
730 | if (!chVTIsArmed(&_delayTimer)) {
|
||
731 | chEvtRegisterMask(&_eventSourceDelay, &_eventListenerDelay, timermask); |
||
732 | chVTSet(&_delayTimer, chTimeUS2I(AOS_SSSP_TIMEOUT), _timerCallback, &_eventSourceDelay); |
||
733 | } |
||
734 | |||
735 | // wait for any event to occur (do not apply any filters in order not to miss any events)
|
||
736 | mask = chEvtWaitOne(ALL_EVENTS); |
||
737 | |||
738 | // GPIO event
|
||
739 | if (mask & gpiolistener->events) {
|
||
740 | // retreive flags without clearing them
|
||
741 | flags = gpiolistener->flags; |
||
742 | apalControlGpioGet(&moduleSsspGpioS, &sstate); |
||
743 | if (flags == sflags) {
|
||
744 | apalControlGpioGet(&moduleSsspGpioS, &sstate); |
||
745 | // if this was the end of a pulse
|
||
746 | if (sstate == APAL_GPIO_OFF) {
|
||
747 | // restart the timer
|
||
748 | chVTReset(&_delayTimer); |
||
749 | chVTSet(&_delayTimer, chTimeUS2I(AOS_SSSP_TIMEOUT), _timerCallback, &_eventSourceDelay); |
||
750 | // increment the identifier
|
||
751 | ++(*identifier); |
||
752 | } |
||
753 | } |
||
754 | } |
||
755 | // timer event
|
||
756 | else if (mask & _eventListenerDelay.events) { |
||
757 | // unregister event
|
||
758 | chEvtUnregister(&_eventSourceDelay, &_eventListenerDelay); |
||
759 | } |
||
760 | // any further events must be handled externally
|
||
761 | |||
762 | return mask;
|
||
763 | } |
||
764 | |||
765 | #endif /* (AMIROOS_CFG_SSSP_SHUTDOWN == true) */ |
||
766 | |||
767 | c218345a | Thomas Schöpping | #if ((AMIROOS_CFG_SSSP_MASTER != true) && (AMIROOS_CFG_PROFILE == true)) || defined(__DOXYGEN__) |
768 | |||
769 | /**
|
||
770 | * @brief Retreive the offset between local clock and system synchronization signal.
|
||
771 | *
|
||
772 | * @return
|
||
773 | */
|
||
774 | float aosSsspGetSyncSkew(void) |
||
775 | { |
||
776 | return _syncskew;
|
||
777 | } |
||
778 | |||
779 | #endif /* (AMIROOS_CFG_SSSP_MASTER != true) && (AMIROOS_CFG_PROFILE == true) */ |
||
780 | |||
781 | cda14729 | Thomas Schöpping | #endif /* (AMIROOS_CFG_SSSP_ENABLE == true) */ |
782 | |||
783 | /** @} */ |