amiro-os / core / src / aos_sssp.c @ a93a1019
History | View | Annotate | Download (47.6 KB)
1 | cda14729 | Thomas Schöpping | /*
|
---|---|---|---|
2 | AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
|
||
3 | 96621a83 | Thomas Schöpping | Copyright (C) 2016..2020 Thomas Schöpping et al.
|
4 | cda14729 | Thomas Schöpping | |
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 | c53ef0b1 | Thomas Schöpping | * @details This timer must not be an AMiRo-OS timer, since delays occurr before system is initialized.
|
87 | cda14729 | Thomas Schöpping | */
|
88 | static virtual_timer_t _delayTimer;
|
||
89 | |||
90 | /**
|
||
91 | * @brief Event source for the delay timer.
|
||
92 | */
|
||
93 | c53ef0b1 | Thomas Schöpping | static event_source_t _delayEventSource;
|
94 | cda14729 | Thomas Schöpping | |
95 | /**
|
||
96 | * @brief Event listener for the delay event.
|
||
97 | */
|
||
98 | c53ef0b1 | Thomas Schöpping | static event_listener_t _delayEventListener;
|
99 | cda14729 | Thomas Schöpping | |
100 | /******************************************************************************/
|
||
101 | /* LOCAL FUNCTIONS */
|
||
102 | /******************************************************************************/
|
||
103 | |||
104 | c218345a | Thomas Schöpping | #if (AMIROOS_CFG_SSSP_MASTER != true) || defined(__DOXYGEN__) |
105 | |||
106 | /**
|
||
107 | c53ef0b1 | Thomas Schöpping | * @brief Callback function for the S signal interrupt.
|
108 | c218345a | Thomas Schöpping | *
|
109 | * @param[in] args Pointer to the GPIO line identifier.
|
||
110 | */
|
||
111 | static void _gpioCallbackSSignal(void *args) |
||
112 | { |
||
113 | aosDbgCheck((args != NULL) && (*((ioline_t*)args) != PAL_NOLINE) && (PAL_PAD(*((ioline_t*)args)) < sizeof(eventflags_t) * 8)); |
||
114 | |||
115 | apalControlGpioState_t s; |
||
116 | aos_timestamp_t t; |
||
117 | |||
118 | chSysLockFromISR(); |
||
119 | |||
120 | // if the system is in operation phase
|
||
121 | if (aos.sssp.stage == AOS_SSSP_STAGE_OPERATION) {
|
||
122 | // read signal S
|
||
123 | c53ef0b1 | Thomas Schöpping | apalControlGpioGet(moduleSsspSignalS(), &s); |
124 | c218345a | Thomas Schöpping | // if S was toggled from on to off
|
125 | if (s == APAL_GPIO_OFF) {
|
||
126 | // get current uptime
|
||
127 | aosSysGetUptimeX(&t); |
||
128 | // align the uptime with the synchronization period
|
||
129 | t %= AMIROOS_CFG_SSSP_SYSSYNCPERIOD; |
||
130 | if (t < AMIROOS_CFG_SSSP_SYSSYNCPERIOD / 2) { |
||
131 | *_uptime -= t; |
||
132 | #if (AMIROOS_CFG_PROFILE == true) |
||
133 | _syncskew = ((1.0f - SYNCSKEW_SMOOTHFACTOR) * _syncskew) + (SYNCSKEW_SMOOTHFACTOR * t); |
||
134 | #endif /* (AMIROOS_CFG_PROFILE == true) */ |
||
135 | } else {
|
||
136 | t = AMIROOS_CFG_SSSP_SYSSYNCPERIOD - t; |
||
137 | *_uptime += t; |
||
138 | #if (AMIROOS_CFG_PROFILE == true) |
||
139 | _syncskew = ((1.0f - SYNCSKEW_SMOOTHFACTOR) * _syncskew) - (SYNCSKEW_SMOOTHFACTOR * t); |
||
140 | #endif /* (AMIROOS_CFG_PROFILE == true) */ |
||
141 | } |
||
142 | } |
||
143 | } |
||
144 | |||
145 | // broadcast event
|
||
146 | chEvtBroadcastFlagsI(&aos.events.gpio, AOS_GPIOEVENT_FLAG(PAL_PAD(*((ioline_t*)args)))); |
||
147 | chSysUnlockFromISR(); |
||
148 | |||
149 | return;
|
||
150 | } |
||
151 | |||
152 | #endif /* (AMIROOS_CFG_SSSP_MASTER != true) */ |
||
153 | |||
154 | #if (AMIROOS_CFG_SSSP_MASTER == true) || defined (__DOXYGEN__) |
||
155 | |||
156 | /**
|
||
157 | * @brief Periodic system synchronization callback function.
|
||
158 | c53ef0b1 | Thomas Schöpping | * @details Toggles the S signal and reconfigures the system synchronization timer.
|
159 | c218345a | Thomas Schöpping | *
|
160 | * @param[in] par Unused parameters.
|
||
161 | */
|
||
162 | static void _syncTimerCallback(void* par) |
||
163 | { |
||
164 | (void)par;
|
||
165 | |||
166 | c53ef0b1 | Thomas Schöpping | // local variables
|
167 | c218345a | Thomas Schöpping | apalControlGpioState_t state; |
168 | aos_timestamp_t uptime; |
||
169 | |||
170 | chSysLockFromISR(); |
||
171 | // toggle and read signal S
|
||
172 | c53ef0b1 | Thomas Schöpping | apalGpioToggle(moduleSsspSignalS()->gpio); |
173 | apalControlGpioGet(moduleSsspSignalS(), &state); |
||
174 | c218345a | Thomas Schöpping | // if S was toggled from off to on
|
175 | if (state == APAL_GPIO_ON) {
|
||
176 | // reconfigure the timer precisely, because the logically falling edge (next interrupt) snychronizes the system time
|
||
177 | _synctime += AMIROOS_CFG_SSSP_SYSSYNCPERIOD; |
||
178 | aosSysGetUptimeX(&uptime); |
||
179 | c53ef0b1 | Thomas Schöpping | chVTSetI(&_synctimer, chTimeUS2I((time_usecs_t)(_synctime - uptime)), _syncTimerCallback, NULL);
|
180 | c218345a | Thomas Schöpping | } |
181 | // if S was toggled from on to off
|
||
182 | else /* if (state == APAL_GPIO_OFF) */ { |
||
183 | // reconfigure the timer (lazy)
|
||
184 | chVTSetI(&_synctimer, chTimeUS2I(AMIROOS_CFG_SSSP_SYSSYNCPERIOD / 2), _syncTimerCallback, NULL); |
||
185 | } |
||
186 | chSysUnlockFromISR(); |
||
187 | |||
188 | return;
|
||
189 | } |
||
190 | |||
191 | /**
|
||
192 | * @brief Start the timer that toggles S for synchronization of the system.
|
||
193 | * @note Must be called from a locked context.
|
||
194 | */
|
||
195 | static inline void _syncTimerStartS(void) |
||
196 | { |
||
197 | chDbgCheckClassS(); |
||
198 | |||
199 | // start synchronization timer
|
||
200 | // The first iteration of the timer is set to the next 'center' of a 'slice'.
|
||
201 | aos_timestamp_t t; |
||
202 | aosSysGetUptimeX(&t); |
||
203 | t = AMIROOS_CFG_SSSP_SYSSYNCPERIOD - (t % AMIROOS_CFG_SSSP_SYSSYNCPERIOD); |
||
204 | c53ef0b1 | Thomas Schöpping | chVTSetI(&_synctimer, chTimeUS2I((time_usecs_t)((t > (AMIROOS_CFG_SSSP_SYSSYNCPERIOD / 2)) ? (t - (AMIROOS_CFG_SSSP_SYSSYNCPERIOD / 2)) : (t + (AMIROOS_CFG_SSSP_SYSSYNCPERIOD / 2)))), _syncTimerCallback, NULL); |
205 | c218345a | Thomas Schöpping | |
206 | return;
|
||
207 | } |
||
208 | |||
209 | #endif /* (AMIROOS_CFG_SSSP_MASTER == true) */ |
||
210 | |||
211 | cda14729 | Thomas Schöpping | /**
|
212 | * @brief General callback function to be used for any local timers.
|
||
213 | *
|
||
214 | * @param[in] par A pointer to an @p event_source_t to be fired.
|
||
215 | */
|
||
216 | static void _timerCallback(void* par) |
||
217 | { |
||
218 | aosDbgCheck(par != NULL);
|
||
219 | |||
220 | chSysLockFromISR(); |
||
221 | chEvtBroadcastI((event_source_t*)par); |
||
222 | chSysUnlockFromISR(); |
||
223 | |||
224 | return;
|
||
225 | } |
||
226 | |||
227 | /**
|
||
228 | * @brief Waits for the S signal to switch to the desired state.
|
||
229 | *
|
||
230 | * @param[in] listener Pointer to the GPIO event listener to be used.
|
||
231 | * @param[in] signalstate Desired state of the S signal ti be waited for.
|
||
232 | * @param[out] received Output variable to store the received event mask to.
|
||
233 | *
|
||
234 | * @return Status, indicating whether the expected event was received.
|
||
235 | */
|
||
236 | c53ef0b1 | Thomas Schöpping | static inline aos_status_t _waitForS(event_listener_t* listener, apalControlGpioState_t signalstate, eventmask_t* received) |
237 | cda14729 | Thomas Schöpping | { |
238 | aosDbgCheck(listener != NULL);
|
||
239 | aosDbgCheck(received != NULL);
|
||
240 | |||
241 | c53ef0b1 | Thomas Schöpping | // local variables
|
242 | aos_status_t status = AOS_FAILURE; |
||
243 | |||
244 | cda14729 | Thomas Schöpping | // wait for the next event (do not apply any filters in order not to miss any events)
|
245 | *received = chEvtWaitOne(ALL_EVENTS); |
||
246 | // if the correct event was triggered
|
||
247 | c53ef0b1 | Thomas Schöpping | if (*received & listener->events) {
|
248 | cda14729 | Thomas Schöpping | apalControlGpioState_t s; |
249 | c53ef0b1 | Thomas Schöpping | apalControlGpioGet(moduleSsspSignalS(), &s); |
250 | chSysLock(); |
||
251 | cda14729 | Thomas Schöpping | // only check for the expected event
|
252 | c53ef0b1 | Thomas Schöpping | if ((listener->flags & moduleSsspEventflagS()) && (s == signalstate)) {
|
253 | cda14729 | Thomas Schöpping | // unset the expected flags but keep any other ones
|
254 | c53ef0b1 | Thomas Schöpping | listener->flags &= ~moduleSsspEventflagS(); |
255 | status = AOS_SUCCESS; |
||
256 | cda14729 | Thomas Schöpping | } |
257 | c53ef0b1 | Thomas Schöpping | // if no further flags are set
|
258 | if (listener->flags == 0) { |
||
259 | // clear event
|
||
260 | *received &= ~(listener->events); |
||
261 | } |
||
262 | chSysUnlock(); |
||
263 | cda14729 | Thomas Schöpping | } |
264 | |||
265 | c53ef0b1 | Thomas Schöpping | return status;
|
266 | cda14729 | Thomas Schöpping | } |
267 | |||
268 | /**
|
||
269 | * @brief Uses the local delay timer to setup a timed event and waits for it to fire.
|
||
270 | *
|
||
271 | * @param[in] dt Delay time in microseconds to be set to the timer.
|
||
272 | * @param[in] mask Event mask to be used for the delay timer.
|
||
273 | * @param[out] received Output variable to store the received event mask to.
|
||
274 | *
|
||
275 | * @return Status, indicating whether the expected event (delay timer) was received.
|
||
276 | */
|
||
277 | c53ef0b1 | Thomas Schöpping | static inline aos_status_t _delay(uint32_t dt, eventmask_t mask, eventmask_t* received) |
278 | cda14729 | Thomas Schöpping | { |
279 | aosDbgCheck(dt != TIME_IMMEDIATE); |
||
280 | aosDbgCheck(mask != 0);
|
||
281 | aosDbgCheck(received != NULL);
|
||
282 | |||
283 | // arm the delay timer once
|
||
284 | c53ef0b1 | Thomas Schöpping | if (!chVTIsArmed(&_delayTimer)) {
|
285 | chEvtRegisterMask(&_delayEventSource, &_delayEventListener, mask); |
||
286 | chVTSet(&_delayTimer, chTimeUS2I(dt), _timerCallback, &_delayEventSource); |
||
287 | cda14729 | Thomas Schöpping | } |
288 | |||
289 | // wait for any event to occur (do not apply any filters in order not to miss any events)
|
||
290 | *received = chEvtWaitOne(ALL_EVENTS); |
||
291 | |||
292 | // if the timer event was received, cleanup
|
||
293 | c53ef0b1 | Thomas Schöpping | if (*received & _delayEventListener.events) {
|
294 | chEvtUnregister(&_delayEventSource, &_delayEventListener); |
||
295 | *received &= ~(_delayEventListener.events); |
||
296 | cda14729 | Thomas Schöpping | return AOS_SUCCESS;
|
297 | } |
||
298 | |||
299 | return AOS_FAILURE;
|
||
300 | } |
||
301 | |||
302 | c53ef0b1 | Thomas Schöpping | #if (AMIROOS_CFG_SSSP_MSI == true) || defined(__DOXYGEN__) |
303 | |||
304 | /**
|
||
305 | * @brief Serialize a BCB message.
|
||
306 | * @details The individual primitives are serialized in big-endian fashion.
|
||
307 | *
|
||
308 | * @param[out] buffer Buffer to write the serialized message to.
|
||
309 | * @param[in] message The message to be serialized.
|
||
310 | */
|
||
311 | 88c47fd9 | Thomas Schöpping | static aos_status_t _serializeBcbMessage(uint8_t* buffer, aos_ssspbcbmessage_t message)
|
312 | c53ef0b1 | Thomas Schöpping | { |
313 | aosDbgCheck(buffer != NULL);
|
||
314 | |||
315 | // encode the message depending on its type
|
||
316 | switch (message.type) {
|
||
317 | case AOS_SSSP_BCBMESSAGE_MSIINIT:
|
||
318 | case AOS_SSSP_BCBMESSAGE_MSIABORT:
|
||
319 | { |
||
320 | buffer[0] = message.type;
|
||
321 | return AOS_SUCCESS;
|
||
322 | } |
||
323 | case AOS_SSSP_BCBMESSAGE_MSIID:
|
||
324 | { |
||
325 | buffer[0] = message.type;
|
||
326 | for (size_t byte = 0; byte < sizeof(aos_ssspmoduleid_t); ++byte) { |
||
327 | bc7aed20 | Thomas Schöpping | buffer[byte+1] = (message.payload.id >> ((sizeof(aos_ssspmoduleid_t) - (byte+1)) * 8)) & 0xFF; |
328 | c53ef0b1 | Thomas Schöpping | } |
329 | return AOS_SUCCESS;
|
||
330 | } |
||
331 | default:
|
||
332 | { |
||
333 | return AOS_FAILURE;
|
||
334 | } |
||
335 | } |
||
336 | } |
||
337 | |||
338 | /**
|
||
339 | * @brief Deserialize a BCB message.
|
||
340 | * @details The individual primitives must be serialized in big-endian fashion.
|
||
341 | *
|
||
342 | * @param[out] message Message object to be filled.
|
||
343 | * @param[in] buffer Buffer holding the serialized message.
|
||
344 | */
|
||
345 | 88c47fd9 | Thomas Schöpping | static aos_status_t _deserializeBcbMessage(aos_ssspbcbmessage_t* message, uint8_t* buffer)
|
346 | c53ef0b1 | Thomas Schöpping | { |
347 | aosDbgCheck(message != NULL);
|
||
348 | aosDbgCheck(buffer != NULL);
|
||
349 | |||
350 | // only decode the first byte, which contains the message type
|
||
351 | message->type = buffer[0];
|
||
352 | |||
353 | // decode the message depedning on its type
|
||
354 | switch (message->type) {
|
||
355 | case AOS_SSSP_BCBMESSAGE_MSIINIT:
|
||
356 | case AOS_SSSP_BCBMESSAGE_MSIABORT:
|
||
357 | { |
||
358 | return AOS_SUCCESS;
|
||
359 | } |
||
360 | case AOS_SSSP_BCBMESSAGE_MSIID:
|
||
361 | { |
||
362 | message->payload.id = 0;
|
||
363 | for (size_t byte = 0; byte < sizeof(aos_ssspmoduleid_t); ++byte) { |
||
364 | bc7aed20 | Thomas Schöpping | message->payload.id |= (aos_ssspmoduleid_t)(buffer[byte+1] << ((sizeof(aos_ssspmoduleid_t) - (byte+1)) * 8)); |
365 | c53ef0b1 | Thomas Schöpping | } |
366 | return AOS_SUCCESS;
|
||
367 | } |
||
368 | default:
|
||
369 | { |
||
370 | message->type = AOS_SSSP_BCBMESSAGE_INVALID; |
||
371 | return AOS_FAILURE;
|
||
372 | } |
||
373 | } |
||
374 | } |
||
375 | |||
376 | /**
|
||
377 | * @brief Common outro of the module stack initialization (MSI).
|
||
378 | * @details This function must be called on failure, success and if MSI is skipped.
|
||
379 | *
|
||
380 | * @param[in] msidata Pointer to the temporary data structure used during MSI.
|
||
381 | */
|
||
382 | 88c47fd9 | Thomas Schöpping | static void _msiOutro(aos_ssspmsidata_t* msidata) |
383 | c53ef0b1 | Thomas Schöpping | { |
384 | aosDbgCheck(msidata != NULL);
|
||
385 | |||
386 | // local variables
|
||
387 | eventmask_t mask = 0;
|
||
388 | |||
389 | // start the internal uptime aggregation
|
||
390 | chSysLock(); |
||
391 | aosSysStartUptimeS(); |
||
392 | #if (AMIROOS_CFG_SSSP_MASTER == true) |
||
393 | // start toggling S for system synchronization
|
||
394 | _syncTimerStartS(); |
||
395 | #endif /* (AMIROOS_CFG_SSSP_MASTER == true) */ |
||
396 | chSysUnlock(); |
||
397 | |||
398 | // reset delay timer
|
||
399 | chVTIsArmed(&_delayTimer); |
||
400 | // unregister delay events
|
||
401 | mask |= _delayEventListener.events; |
||
402 | chEvtUnregister(&_delayEventSource, &_delayEventListener); |
||
403 | |||
404 | #if (AMIROOS_CFG_SSSP_STACK_END != true) |
||
405 | // deactivate UP signal
|
||
406 | apalControlGpioSet(moduleSsspSignalUP(), APAL_GPIO_OFF); |
||
407 | #endif /* (AMIROOS_CFG_SSSP_STACK_END != true) */ |
||
408 | |||
409 | // reset timeout timer
|
||
410 | chVTReset(&msidata->timeout.timer); |
||
411 | // unregister timeout events
|
||
412 | mask |= msidata->timeout.eventlistener.events; |
||
413 | chEvtUnregister(&msidata->timeout.eventsource, &msidata->timeout.eventlistener); |
||
414 | |||
415 | // discard any pending timing events
|
||
416 | chEvtWaitAnyTimeout(mask, TIME_IMMEDIATE); |
||
417 | |||
418 | // proceed to operation phase
|
||
419 | aos.sssp.stage = AOS_SSSP_STAGE_OPERATION; |
||
420 | |||
421 | return;
|
||
422 | } |
||
423 | |||
424 | #endif /* (AMIROOS_CFG_SSSP_MSI == true) */ |
||
425 | |||
426 | cda14729 | Thomas Schöpping | /******************************************************************************/
|
427 | /* EXPORTED FUNCTIONS */
|
||
428 | /******************************************************************************/
|
||
429 | |||
430 | /**
|
||
431 | * @brief Initialize all SSSP related data.
|
||
432 | */
|
||
433 | c218345a | Thomas Schöpping | void aosSsspInit(aos_timestamp_t* system_uptime)
|
434 | cda14729 | Thomas Schöpping | { |
435 | c218345a | Thomas Schöpping | aosDbgCheck(system_uptime != NULL);
|
436 | |||
437 | cda14729 | Thomas Schöpping | #if (AMIROOS_CFG_SSSP_STARTUP == true) |
438 | // AMiRo-OS has to perform the basic initialization
|
||
439 | aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_1_1; |
||
440 | #else /* (AMIROOS_CFG_SSSP_STARTUP == true) */ |
||
441 | // basic initialization was already performed by a bootloader
|
||
442 | aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_2_1; |
||
443 | #endif /* (AMIROOS_CFG_SSSP_STARTUP == true) */ |
||
444 | |||
445 | c53ef0b1 | Thomas Schöpping | // module ID is initialized as 'invalid'
|
446 | aos.sssp.moduleId = AOS_SSSP_MODULEID_INVALID; |
||
447 | |||
448 | #if (AMIROOS_CFG_DBG == true) |
||
449 | 510b93cc | Thomas Schöpping | // check all SSSP signals for correct state
|
450 | c53ef0b1 | Thomas Schöpping | { |
451 | apalControlGpioState_t state; |
||
452 | apalControlGpioGet(moduleSsspSignalS(), &state); |
||
453 | aosDbgAssert(state == APAL_GPIO_ON); |
||
454 | apalControlGpioGet(moduleSsspSignalPD(), &state); |
||
455 | aosDbgAssert(state == APAL_GPIO_OFF); |
||
456 | c218345a | Thomas Schöpping | #if (AMIROOS_CFG_SSSP_MSI == true) |
457 | 510b93cc | Thomas Schöpping | #if (AMIROOS_CFG_SSSP_STACK_START != true) |
458 | c53ef0b1 | Thomas Schöpping | apalControlGpioGet(moduleSsspSignalDN(), &state); |
459 | aosDbgAssert(state == APAL_GPIO_OFF); |
||
460 | 510b93cc | Thomas Schöpping | #endif /* (AMIROOS_CFG_SSSP_STACK_START != true) */ |
461 | c53ef0b1 | Thomas Schöpping | #if (AMIROOS_CFG_SSSP_STACK_END != true) |
462 | apalControlGpioGet(moduleSsspSignalUP(), &state); |
||
463 | aosDbgAssert(state == APAL_GPIO_OFF); |
||
464 | #endif /* (AMIROOS_CFG_SSSP_END_START != true) */ |
||
465 | c218345a | Thomas Schöpping | #endif /* (AMIROOS_CFG_SSSP_MSI == true) */ |
466 | c53ef0b1 | Thomas Schöpping | } |
467 | #endif /* (AMIROOS_CFG_DBG == true) */ |
||
468 | 510b93cc | Thomas Schöpping | |
469 | cda14729 | Thomas Schöpping | // initialize static variables
|
470 | c218345a | Thomas Schöpping | _uptime = system_uptime; |
471 | #if (AMIROOS_CFG_SSSP_MASTER == true) |
||
472 | chVTObjectInit(&_synctimer); |
||
473 | _synctime = 0;
|
||
474 | #endif /* (AMIROOS_CFG_SSSP_MASTER == true) */ |
||
475 | #if (AMIROOS_CFG_SSSP_MASTER != true) && (AMIROOS_CFG_PROFILE == true) |
||
476 | _syncskew = 0.0f; |
||
477 | #endif /* (AMIROOS_CFG_SSSP_MASTER != true) && (AMIROOS_CFG_PROFILE == true) */ |
||
478 | cda14729 | Thomas Schöpping | chVTObjectInit(&_delayTimer); |
479 | c53ef0b1 | Thomas Schöpping | chEvtObjectInit(&_delayEventSource); |
480 | cda14729 | Thomas Schöpping | |
481 | c218345a | Thomas Schöpping | // signal interrupt setup
|
482 | c53ef0b1 | Thomas Schöpping | palSetLineCallback(moduleSsspSignalPD()->gpio->line, aosSysGetStdGpioCallback(), &moduleSsspSignalPD()->gpio->line); |
483 | palEnableLineEvent(moduleSsspSignalPD()->gpio->line, APAL2CH_EDGE(moduleSsspSignalPD()->meta.edge)); |
||
484 | c218345a | Thomas Schöpping | #if (AMIROOS_CFG_SSSP_MASTER == true) |
485 | c53ef0b1 | Thomas Schöpping | palSetLineCallback(moduleSsspSignalS()->gpio->line, aosSysGetStdGpioCallback(), &moduleSsspSignalS()->gpio->line); |
486 | c218345a | Thomas Schöpping | #else /* (AMIROOS_CFG_SSSP_MASTER == true) */ |
487 | c53ef0b1 | Thomas Schöpping | palSetLineCallback(moduleSsspSignalS()->gpio->line, _gpioCallbackSSignal, &moduleSsspSignalS()->gpio->line); |
488 | c218345a | Thomas Schöpping | #endif /* (AMIROOS_CFG_SSSP_MASTER == true) */ |
489 | c53ef0b1 | Thomas Schöpping | palEnableLineEvent(moduleSsspSignalS()->gpio->line, APAL2CH_EDGE(moduleSsspSignalS()->meta.edge)); |
490 | c218345a | Thomas Schöpping | #if (AMIROOS_CFG_SSSP_MSI == true) |
491 | #if (AMIROOS_CFG_SSSP_STACK_START != true) |
||
492 | c53ef0b1 | Thomas Schöpping | palSetLineCallback(moduleSsspSignalDN()->gpio->line, aosSysGetStdGpioCallback(), &moduleSsspSignalDN()->gpio->line); |
493 | palEnableLineEvent(moduleSsspSignalDN()->gpio->line, APAL2CH_EDGE(moduleSsspSignalDN()->meta.edge)); |
||
494 | c218345a | Thomas Schöpping | #endif /* (AMIROOS_CFG_SSSP_STACK_START != true) */ |
495 | #if (AMIROOS_CFG_SSSP_STACK_END != true) |
||
496 | c53ef0b1 | Thomas Schöpping | palSetLineCallback(moduleSsspSignalUP()->gpio->line, aosSysGetStdGpioCallback(), &moduleSsspSignalUP()->gpio->line); |
497 | palEnableLineEvent(moduleSsspSignalUP()->gpio->line, APAL2CH_EDGE(moduleSsspSignalUP()->meta.edge)); |
||
498 | c218345a | Thomas Schöpping | #endif /* (AMIROOS_CFG_SSSP_STACK_END != true) */ |
499 | #endif /* (AMIROOS_CFG_SSSP_MSI == true) */ |
||
500 | |||
501 | cda14729 | Thomas Schöpping | return;
|
502 | } |
||
503 | |||
504 | /**
|
||
505 | * @brief Proceed to the next SSSP stage.
|
||
506 | c218345a | Thomas Schöpping | * @note Calling this function when in operation phase is invalid.
|
507 | * The function aosSsspShutdownInit() must be used instead.
|
||
508 | cda14729 | Thomas Schöpping | *
|
509 | * @param[in] listener An optional listener, in case the system has to wait for a specific event.
|
||
510 | * @param[in] mask If the stage transition involves a timer event (handled internally by this function),
|
||
511 | * the given input value of this parameter defines the mask to be used for that event.
|
||
512 | * 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.
|
||
513 | * @param[out] received Output variable to store the received event mask to.
|
||
514 | *
|
||
515 | * @return Status, indicating whether proceeding in the protocol was successful.
|
||
516 | */
|
||
517 | c53ef0b1 | Thomas Schöpping | aos_status_t aosSsspProceed(event_listener_t* listener, eventmask_t mask, eventmask_t* received) |
518 | cda14729 | Thomas Schöpping | { |
519 | // local variables
|
||
520 | #pragma GCC diagnostic push
|
||
521 | #pragma GCC diagnostic ignored "-Wunused-but-set-variable" |
||
522 | static aos_ssspstage_t laststage = AOS_SSSP_STAGE_UNDEFINED;
|
||
523 | #pragma GCC diagnostic pop
|
||
524 | aos_ssspstage_t nextstage = aos.sssp.stage; |
||
525 | |||
526 | // behaviour depends on current SSSP stage of the system
|
||
527 | switch (aos.sssp.stage) {
|
||
528 | #if (AMIROOS_CFG_SSSP_STARTUP == true) |
||
529 | |||
530 | /*
|
||
531 | * Deactivate S signal.
|
||
532 | * Master node delays execution by one period AOS_SSSP_DELAY.
|
||
533 | */
|
||
534 | case AOS_SSSP_STAGE_STARTUP_1_1:
|
||
535 | { |
||
536 | #if (AMIROOS_CFG_SSSP_MASTER == true) |
||
537 | aosDbgCheck(listener == NULL);
|
||
538 | aosDbgCheck(mask != 0);
|
||
539 | aosDbgCheck(received != NULL);
|
||
540 | |||
541 | // delay execution and deactivate the S signal on success
|
||
542 | c53ef0b1 | Thomas Schöpping | if (_delay(AOS_SSSP_DELAY, mask, received) == AOS_SUCCESS) {
|
543 | apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_OFF); |
||
544 | cda14729 | Thomas Schöpping | nextstage = AOS_SSSP_STAGE_STARTUP_1_2; |
545 | } |
||
546 | #else /* (AMIROOS_CFG_SSSP_MASTER == true) */ |
||
547 | aosDbgCheck(listener == NULL);
|
||
548 | aosDbgCheck(mask == 0);
|
||
549 | aosDbgCheck(received == NULL);
|
||
550 | |||
551 | // deactivate S signal and proceed
|
||
552 | c53ef0b1 | Thomas Schöpping | apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_OFF); |
553 | cda14729 | Thomas Schöpping | nextstage = AOS_SSSP_STAGE_STARTUP_1_2; |
554 | #endif /* (AMIROOS_CFG_SSSP_MASTER == true) */ |
||
555 | break;
|
||
556 | } |
||
557 | |||
558 | /*
|
||
559 | * Wait for the S signal to become inactive.
|
||
560 | */
|
||
561 | case AOS_SSSP_STAGE_STARTUP_1_2:
|
||
562 | { |
||
563 | aosDbgCheck(listener != NULL);
|
||
564 | aosDbgCheck(mask == listener->events); |
||
565 | aosDbgCheck(received != NULL);
|
||
566 | |||
567 | // wait for the S signal to become inactive and proceed on success
|
||
568 | c53ef0b1 | Thomas Schöpping | if (_waitForS(listener, APAL_GPIO_OFF, received) == AOS_SUCCESS) {
|
569 | cda14729 | Thomas Schöpping | nextstage = AOS_SSSP_STAGE_STARTUP_1_3; |
570 | } |
||
571 | break;
|
||
572 | } |
||
573 | |||
574 | /*
|
||
575 | * Wait for the S signal to be activated by the master module.
|
||
576 | * The master delays execution by one period AOS_SSSP_DELAY.
|
||
577 | */
|
||
578 | case AOS_SSSP_STAGE_STARTUP_1_3:
|
||
579 | { |
||
580 | #if (AMIROOS_CFG_SSSP_MASTER == true) |
||
581 | aosDbgCheck(listener == NULL);
|
||
582 | aosDbgCheck(mask != 0);
|
||
583 | aosDbgCheck(received != NULL);
|
||
584 | |||
585 | // delay execution and deactivate the S signal on success
|
||
586 | c53ef0b1 | Thomas Schöpping | if (_delay(AOS_SSSP_DELAY, mask, received) == AOS_SUCCESS) {
|
587 | apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_ON); |
||
588 | cda14729 | Thomas Schöpping | nextstage = AOS_SSSP_STAGE_STARTUP_2_1; |
589 | } |
||
590 | #else /* (AMIROOS_CFG_SSSP_MASTER == true) */ |
||
591 | aosDbgCheck(listener != NULL);
|
||
592 | aosDbgCheck(mask == listener->events); |
||
593 | aosDbgCheck(received != NULL);
|
||
594 | |||
595 | // wait for the S signal to become active and activate it as well and proceed on success
|
||
596 | c53ef0b1 | Thomas Schöpping | if (_waitForS(listener, APAL_GPIO_ON, received) == AOS_SUCCESS) {
|
597 | apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_ON); |
||
598 | cda14729 | Thomas Schöpping | nextstage = AOS_SSSP_STAGE_STARTUP_2_1; |
599 | } |
||
600 | #endif /* (AMIROOS_CFG_SSSP_MASTER == true) */ |
||
601 | break;
|
||
602 | } |
||
603 | |||
604 | #endif /* (AMIROOS_CFG_SSSP_STARTUP == true) */ |
||
605 | |||
606 | /*
|
||
607 | * Deactivate S signal.
|
||
608 | * Master node delays execution by one period AOS_SSSP_DELAY
|
||
609 | */
|
||
610 | case AOS_SSSP_STAGE_STARTUP_2_1:
|
||
611 | { |
||
612 | #if (AMIROOS_CFG_SSSP_MASTER == true) |
||
613 | aosDbgCheck(listener == NULL);
|
||
614 | aosDbgCheck(mask != 0);
|
||
615 | aosDbgCheck(received != NULL);
|
||
616 | |||
617 | // delay execution and deactivate the S signal on success
|
||
618 | c53ef0b1 | Thomas Schöpping | if (_delay(AOS_SSSP_DELAY, mask, received) == AOS_SUCCESS) {
|
619 | apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_OFF); |
||
620 | cda14729 | Thomas Schöpping | nextstage = AOS_SSSP_STAGE_STARTUP_2_2; |
621 | c53ef0b1 | Thomas Schöpping | } else {
|
622 | aosprintf(".");
|
||
623 | cda14729 | Thomas Schöpping | } |
624 | #else /* (AMIROOS_CFG_SSSP_MASTER == true) */ |
||
625 | aosDbgCheck(listener == NULL);
|
||
626 | aosDbgCheck(mask == 0);
|
||
627 | aosDbgCheck(received == NULL);
|
||
628 | |||
629 | // deactivate S signal and proceed
|
||
630 | c53ef0b1 | Thomas Schöpping | apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_OFF); |
631 | cda14729 | Thomas Schöpping | nextstage = AOS_SSSP_STAGE_STARTUP_2_2; |
632 | mask = 0;
|
||
633 | #endif /* (AMIROOS_CFG_SSSP_MASTER == true) */ |
||
634 | break;
|
||
635 | } |
||
636 | |||
637 | /*
|
||
638 | * Wait for the S signal to become inactive.
|
||
639 | c218345a | Thomas Schöpping | * When proceeding to operation phase, the master starts toggling S for synchronization
|
640 | cda14729 | Thomas Schöpping | */
|
641 | case AOS_SSSP_STAGE_STARTUP_2_2:
|
||
642 | { |
||
643 | aosDbgCheck(listener != NULL);
|
||
644 | aosDbgCheck(mask == listener->events); |
||
645 | aosDbgCheck(received != NULL);
|
||
646 | |||
647 | // wait for the S signal to become inactive and proceed on success
|
||
648 | c53ef0b1 | Thomas Schöpping | if (_waitForS(listener, APAL_GPIO_OFF, received) == AOS_SUCCESS) {
|
649 | cda14729 | Thomas Schöpping | #if (AMIROOS_CFG_SSSP_MSI == true) |
650 | nextstage = AOS_SSSP_STAGE_STARTUP_3; |
||
651 | #else /* (AMIROOS_CFG_SSSP_MSI == true) */ |
||
652 | c218345a | Thomas Schöpping | // start the internal uptime aggregation
|
653 | c53ef0b1 | Thomas Schöpping | chSysLock(); |
654 | c218345a | Thomas Schöpping | aosSysStartUptimeS(); |
655 | #if (AMIROOS_CFG_SSSP_MASTER == true) |
||
656 | // start toggling S for system synchronization
|
||
657 | _syncTimerStartS(); |
||
658 | #endif /* (AMIROOS_CFG_SSSP_MASTER == true) */ |
||
659 | chSysUnlock(); |
||
660 | cda14729 | Thomas Schöpping | nextstage = AOS_SSSP_STAGE_OPERATION; |
661 | #endif /* (AMIROOS_CFG_SSSP_MSI == true) */ |
||
662 | } |
||
663 | break;
|
||
664 | } |
||
665 | |||
666 | c53ef0b1 | Thomas Schöpping | /*
|
667 | * PLEASE NOTE:
|
||
668 | * Stage transitions during MSI are not hanlded by thins function but are executed in aosSsspMsi().
|
||
669 | */
|
||
670 | cda14729 | Thomas Schöpping | |
671 | /*
|
||
672 | c218345a | Thomas Schöpping | * Invalid operation.
|
673 | * Shutdon must be initiatid via the aosSsspShutdownInit() function.
|
||
674 | */
|
||
675 | case AOS_SSSP_STAGE_OPERATION:
|
||
676 | { |
||
677 | aosDbgAssertMsg(false, "in order to exit operation phase, aosSsspShutdownInit() function must be used"); |
||
678 | break;
|
||
679 | } |
||
680 | |||
681 | /*
|
||
682 | cda14729 | Thomas Schöpping | * Delay execution by one perion AOS_SSSP_DELAY, deactivate the SYNC signal and proceed.
|
683 | * NOTE: Actually only the module that initiated the shutdown has to delay execution here.
|
||
684 | * For the sake of simlicity though, each module delays execution.
|
||
685 | */
|
||
686 | case AOS_SSSP_STAGE_SHUTDOWN_1_2:
|
||
687 | { |
||
688 | aosDbgCheck(listener == NULL);
|
||
689 | aosDbgCheck(mask == 0);
|
||
690 | aosDbgCheck(received == NULL);
|
||
691 | |||
692 | // delay execution
|
||
693 | aosThdUSleep(AOS_SSSP_DELAY); |
||
694 | // deactivate S signal
|
||
695 | c53ef0b1 | Thomas Schöpping | apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_OFF); |
696 | cda14729 | Thomas Schöpping | nextstage = AOS_SSSP_STAGE_SHUTDOWN_1_3; |
697 | break;
|
||
698 | } |
||
699 | |||
700 | #if (AMIROOS_CFG_SSSP_SHUTDOWN == true) |
||
701 | |||
702 | /*
|
||
703 | * Wait for S signal to become inactive.
|
||
704 | */
|
||
705 | case AOS_SSSP_STAGE_SHUTDOWN_1_3:
|
||
706 | { |
||
707 | aosDbgCheck(listener != NULL);
|
||
708 | aosDbgCheck(mask == listener->events); |
||
709 | aosDbgCheck(received != NULL);
|
||
710 | |||
711 | // wait for the S signal to become inactive and proceed on success
|
||
712 | c53ef0b1 | Thomas Schöpping | if (_waitForS(listener, APAL_GPIO_OFF, received) == AOS_SUCCESS) {
|
713 | cda14729 | Thomas Schöpping | nextstage = AOS_SSSP_STAGE_SHUTDOWN_2_1; |
714 | } |
||
715 | break;
|
||
716 | } |
||
717 | |||
718 | /*
|
||
719 | * Evaluate PD signal to determine whether a shutdown or restart is requested.
|
||
720 | * The logical state is returned by the function call.
|
||
721 | */
|
||
722 | case AOS_SSSP_STAGE_SHUTDOWN_2_1:
|
||
723 | { |
||
724 | aosDbgCheck(listener == NULL);
|
||
725 | aosDbgCheck(mask == 0);
|
||
726 | aosDbgCheck(received != NULL);
|
||
727 | |||
728 | // evaluate PD signal
|
||
729 | apalControlGpioState_t pd; |
||
730 | c53ef0b1 | Thomas Schöpping | apalControlGpioGet(moduleSsspSignalPD(), &pd); |
731 | cda14729 | Thomas Schöpping | *received = (pd == APAL_GPIO_ON) ? (eventmask_t)~0 : 0; |
732 | nextstage = AOS_SSSP_STAGE_SHUTDOWN_2_2; |
||
733 | break;
|
||
734 | } |
||
735 | |||
736 | /*
|
||
737 | * Proceed with no further actions required.
|
||
738 | */
|
||
739 | case AOS_SSSP_STAGE_SHUTDOWN_2_2:
|
||
740 | { |
||
741 | aosDbgCheck(listener == NULL);
|
||
742 | aosDbgCheck(mask == 0);
|
||
743 | aosDbgCheck(received == NULL);
|
||
744 | |||
745 | nextstage = AOS_SSSP_STAGE_SHUTDOWN_2_3; |
||
746 | break;
|
||
747 | } |
||
748 | |||
749 | #endif /* (AMIROOS_CFG_SSSP_SHUTDOWN == true) */ |
||
750 | |||
751 | default:
|
||
752 | { |
||
753 | // this case must never occur!
|
||
754 | aosDbgAssertMsg(false, "Invalid SSSP stage tranition occurred"); |
||
755 | break;
|
||
756 | } |
||
757 | } /* end of switch (aos.sssp.stage) */
|
||
758 | |||
759 | // outro and return
|
||
760 | laststage = aos.sssp.stage; |
||
761 | const aos_status_t status = (nextstage > aos.sssp.stage) ? AOS_SUCCESS : AOS_FAILURE;
|
||
762 | aos.sssp.stage = nextstage; |
||
763 | |||
764 | return status;
|
||
765 | } |
||
766 | |||
767 | c53ef0b1 | Thomas Schöpping | #if (AMIROOS_CFG_SSSP_MSI == true) || defined(__DOXYGEN__) |
768 | |||
769 | /**
|
||
770 | * @brief Initialize MSI data structure.
|
||
771 | *
|
||
772 | * @param[out] msidata Pointer to the MSI data structure to be initialized.
|
||
773 | * @param[in] delayMask Event maks used for delay events.
|
||
774 | * @param[in] timeoutMask Event mask used for timeout events.
|
||
775 | * @param[in] gpioListener Event listener for GPIO events.
|
||
776 | */
|
||
777 | void aosSsspMsiInit(aos_ssspmsidata_t* msidata, eventmask_t delayMask, eventmask_t timeoutMask, event_listener_t* gpioListener)
|
||
778 | { |
||
779 | aosDbgCheck(msidata != NULL);
|
||
780 | aosDbgCheck(gpioListener != NULL);
|
||
781 | |||
782 | // register delay events
|
||
783 | chEvtRegisterMask(&_delayEventSource, &_delayEventListener, delayMask); |
||
784 | |||
785 | // initialize timeout related data
|
||
786 | chVTObjectInit(&msidata->timeout.timer); |
||
787 | chEvtObjectInit(&msidata->timeout.eventsource); |
||
788 | chEvtRegisterMask(&msidata->timeout.eventsource, &msidata->timeout.eventlistener, timeoutMask); |
||
789 | |||
790 | // set GPIO event information
|
||
791 | msidata->signals.eventlistener = gpioListener; |
||
792 | |||
793 | // initialize BCB related data
|
||
794 | msidata->bcb.lastid = AOS_SSSP_MODULEID_INVALID; |
||
795 | |||
796 | return;
|
||
797 | } |
||
798 | |||
799 | /**
|
||
800 | * @brief Execute module stack initialization (MSI).
|
||
801 | *
|
||
802 | * @param[in] msidata Data required for MSI.
|
||
803 | * @param[out] received Output variable to store the received event mask to.
|
||
804 | */
|
||
805 | void aosSsspMsi(aos_ssspmsidata_t* msidata, eventmask_t* received)
|
||
806 | { |
||
807 | aosDbgCheck(msidata != NULL);
|
||
808 | aosDbgCheck(received != NULL);
|
||
809 | |||
810 | /*
|
||
811 | * execute anything that does not depend on BCB messages or events
|
||
812 | */
|
||
813 | switch (aos.sssp.stage) {
|
||
814 | case AOS_SSSP_STAGE_STARTUP_3:
|
||
815 | case AOS_SSSP_STAGE_STARTUP_3_1:
|
||
816 | { |
||
817 | aosDbgPrintf(">>> MSI init\n");
|
||
818 | // setup timeout timer
|
||
819 | chVTSet(&msidata->timeout.timer, chTimeUS2I(AOS_SSSP_TIMEOUT), _timerCallback, &msidata->timeout.eventsource); |
||
820 | // proceed
|
||
821 | #if (AMIROOS_CFG_SSSP_MASTER == true) |
||
822 | aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_1_BROADCASTINIT; |
||
823 | #else /* (AMIROOS_CFG_SSSP_MASTER == true) */ |
||
824 | aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_1_WAITFORINIT; |
||
825 | #endif /* (AMIROOS_CFG_SSSP_MASTER == true) */ |
||
826 | break;
|
||
827 | } |
||
828 | |||
829 | #if (AMIROOS_CFG_SSSP_MASTER == true) |
||
830 | case AOS_SSSP_STAGE_STARTUP_3_1_BROADCASTINIT:
|
||
831 | { |
||
832 | aosDbgPrintf("%u\tsend INIT\t", chVTGetSystemTime());
|
||
833 | // send init command
|
||
834 | msidata->bcb.message.type = AOS_SSSP_BCBMESSAGE_MSIINIT; |
||
835 | _serializeBcbMessage(msidata->bcb.buffer, msidata->bcb.message); |
||
836 | if (moduleSsspBcbTransmit(msidata->bcb.buffer, sizeof(aos_ssspbcbmessage_t)) == AOS_SSSP_BCB_SUCCESS) { |
||
837 | aosDbgPrintf("ok\tS+\t");
|
||
838 | // activate S
|
||
839 | apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_ON); |
||
840 | // restart timeout timer
|
||
841 | chVTSet(&msidata->timeout.timer, chTimeUS2I(AOS_SSSP_TIMEOUT), _timerCallback, &msidata->timeout.eventsource); |
||
842 | // proceed
|
||
843 | #if (AMIROOS_CFG_SSSP_STACK_START == true) |
||
844 | aosDbgPrintf("->start\n");
|
||
845 | aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_2; |
||
846 | #else /* (AMIROOS_CFG_SSSP_STACK_START == true) */ |
||
847 | aosDbgPrintf("->count\n");
|
||
848 | aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_3_WAIT4EVENT; |
||
849 | #endif /* (AMIROOS_CFG_SSSP_STACK_START == true) */ |
||
850 | } else {
|
||
851 | aosDbgPrintf("fail\t->retry\n");
|
||
852 | // retry in next iteration
|
||
853 | } |
||
854 | break;
|
||
855 | } |
||
856 | #endif /* (AMIROOS_CFG_SSSP_MASTER == true) */ |
||
857 | |||
858 | #if (AMIROOS_CFG_SSSP_STACK_START == true) |
||
859 | case AOS_SSSP_STAGE_STARTUP_3_2:
|
||
860 | { |
||
861 | aosDbgPrintf("%u\tstart\t", chVTGetSystemTime());
|
||
862 | // set the own module ID
|
||
863 | aos.sssp.moduleId = 1;
|
||
864 | // broadcast the new ID
|
||
865 | msidata->bcb.message.type = AOS_SSSP_BCBMESSAGE_MSIID; |
||
866 | msidata->bcb.message.payload.id = aos.sssp.moduleId; |
||
867 | aosDbgPrintf("bc ID (%u)\t", msidata->bcb.message.payload.id);
|
||
868 | _serializeBcbMessage(msidata->bcb.buffer, msidata->bcb.message); |
||
869 | if (moduleSsspBcbTransmit(msidata->bcb.buffer, sizeof(aos_ssspbcbmessage_t)) == AOS_SSSP_BCB_SUCCESS) { |
||
870 | aosDbgPrintf("ok\t->count\n");
|
||
871 | // restart timeout timer
|
||
872 | chVTSet(&msidata->timeout.timer, chTimeUS2I(AOS_SSSP_TIMEOUT), _timerCallback, &msidata->timeout.eventsource); |
||
873 | // set delay timer so UP will be activated and S deactivated later
|
||
874 | chVTSet(&_delayTimer, chTimeUS2I(AOS_SSSP_DELAY), _timerCallback, &_delayEventSource); |
||
875 | // store the transmitted ID
|
||
876 | msidata->bcb.lastid = msidata->bcb.message.payload.id; |
||
877 | // proceed
|
||
878 | aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_3_WAIT4EVENT; |
||
879 | } else {
|
||
880 | aosDbgPrintf("fail\t->retry\n");
|
||
881 | // retry next iteration
|
||
882 | } |
||
883 | break;
|
||
884 | } |
||
885 | #endif /* (AMIROOS_CFG_SSSP_STACK_START == true) */ |
||
886 | |||
887 | case AOS_SSSP_STAGE_STARTUP_3_3_BROADCASTID:
|
||
888 | { |
||
889 | // broadcast ID
|
||
890 | msidata->bcb.message.type = AOS_SSSP_BCBMESSAGE_MSIID; |
||
891 | msidata->bcb.message.payload.id = aos.sssp.moduleId; |
||
892 | aosDbgPrintf("%u\tbc ID (%u)\t", chVTGetSystemTime(), msidata->bcb.message.payload.id);
|
||
893 | _serializeBcbMessage(msidata->bcb.buffer, msidata->bcb.message); |
||
894 | if (moduleSsspBcbTransmit(msidata->bcb.buffer, sizeof(aos_ssspbcbmessage_t)) == AOS_SSSP_BCB_SUCCESS) { |
||
895 | aosDbgPrintf("ok->count\n");
|
||
896 | // restart timeout timer
|
||
897 | chVTSet(&msidata->timeout.timer, chTimeUS2I(AOS_SSSP_TIMEOUT), _timerCallback, &msidata->timeout.eventsource); |
||
898 | // set delay timer so UP will be activated and S deactivated later
|
||
899 | chVTSet(&_delayTimer, chTimeUS2I(AOS_SSSP_DELAY), _timerCallback, &_delayEventSource); |
||
900 | // store the transmitted ID
|
||
901 | msidata->bcb.lastid = msidata->bcb.message.payload.id; |
||
902 | // return to receiving
|
||
903 | aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_3_WAIT4EVENT; |
||
904 | } else {
|
||
905 | aosDbgPrintf("fail\t->retry\n");
|
||
906 | // retry next iteration
|
||
907 | } |
||
908 | break;
|
||
909 | } |
||
910 | |||
911 | case AOS_SSSP_STAGE_STARTUP_3_4_ABORTION_INIT:
|
||
912 | { |
||
913 | aosDbgPrintf("%u\tabort\t", chVTGetSystemTime());
|
||
914 | // reset timeout timer
|
||
915 | chVTReset(&msidata->timeout.timer); |
||
916 | // transmit abort message
|
||
917 | msidata->bcb.message.type = AOS_SSSP_BCBMESSAGE_MSIABORT; |
||
918 | _serializeBcbMessage(msidata->bcb.buffer, msidata->bcb.message); |
||
919 | if (moduleSsspBcbTransmit(msidata->bcb.buffer, sizeof(aos_ssspbcbmessage_t)) == AOS_SSSP_BCB_SUCCESS) { |
||
920 | aosDbgPrintf("ok\tS-\t->sync\n");
|
||
921 | // deactivate S
|
||
922 | apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_OFF); |
||
923 | // proceed
|
||
924 | aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_4_ABORTION_SYNC; |
||
925 | } else {
|
||
926 | aosDbgPrintf("fail\t->retry\n");
|
||
927 | // retry next iteration
|
||
928 | } |
||
929 | break;
|
||
930 | } |
||
931 | |||
932 | default:
|
||
933 | { |
||
934 | // all other stages depend on events or BCB messages and are thus handled below
|
||
935 | break;
|
||
936 | } |
||
937 | } |
||
938 | |||
939 | /*
|
||
940 | * handle BCB messages
|
||
941 | */
|
||
942 | msidata->bcb.status = moduleSsspBcbReceive(msidata->bcb.buffer, sizeof(aos_ssspbcbmessage_t));
|
||
943 | switch (msidata->bcb.status) {
|
||
944 | |||
945 | /* VALID BCB MESSAGE
|
||
946 | * A message was received via BCB that seems to be plausible.
|
||
947 | * The first BCB message initiates the sequence once.
|
||
948 | * During MSI an arbitrary number of IDs will be received.
|
||
949 | * Abort messages can be received at any time.
|
||
950 | */
|
||
951 | case AOS_SSSP_BCB_SUCCESS:
|
||
952 | { |
||
953 | aosDbgPrintf("%u\tBCB\t", chVTGetSystemTime());
|
||
954 | // deserialize message and handle types differently
|
||
955 | _deserializeBcbMessage(&msidata->bcb.message, msidata->bcb.buffer); |
||
956 | switch (msidata->bcb.message.type) {
|
||
957 | // initialization message
|
||
958 | case AOS_SSSP_BCBMESSAGE_MSIINIT:
|
||
959 | { |
||
960 | #if (AMIROOS_CFG_SSSP_MASTER == true) |
||
961 | aosDbgPrintf("INIT\t->abort\n");
|
||
962 | // initiate abortion
|
||
963 | aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_4_ABORTION_INIT; |
||
964 | #else /* (AMIROOS_CFG_SSSP_MASTER == true) */ |
||
965 | aosDbgPrintf("INIT\t");
|
||
966 | // check for correct SSSP stage
|
||
967 | if (aos.sssp.stage == AOS_SSSP_STAGE_STARTUP_3_1_WAITFORINIT) {
|
||
968 | aosDbgPrintf("S+\t");
|
||
969 | // activate S
|
||
970 | apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_ON); |
||
971 | // restart timeout timer
|
||
972 | chVTSet(&msidata->timeout.timer, chTimeUS2I(AOS_SSSP_TIMEOUT), _timerCallback, &msidata->timeout.eventsource); |
||
973 | // proceed
|
||
974 | #if (AMIROOS_CFG_SSSP_STACK_START == true) |
||
975 | aosDbgPrintf("->start\n");
|
||
976 | aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_2; |
||
977 | #else /* (AMIROOS_CFG_SSSP_STACK_START == true) */ |
||
978 | aosDbgPrintf("->count\n");
|
||
979 | aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_3_WAIT4EVENT; |
||
980 | #endif /* (AMIROOS_CFG_SSSP_STACK_START == true) */ |
||
981 | } else {
|
||
982 | aosDbgPrintf("->abort\n");
|
||
983 | // initiate abortion
|
||
984 | aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_4_ABORTION_INIT; |
||
985 | } |
||
986 | #endif /* (AMIROOS_CFG_SSSP_MASTER == true) */ |
||
987 | break;
|
||
988 | } |
||
989 | // ID message
|
||
990 | case AOS_SSSP_BCBMESSAGE_MSIID:
|
||
991 | { |
||
992 | aosDbgPrintf("ID (%u)\t", msidata->bcb.message.payload.id);
|
||
993 | // check for correct stage and whether ID was increased
|
||
994 | if (aos.sssp.stage == AOS_SSSP_STAGE_STARTUP_3_3_WAIT4EVENT &&
|
||
995 | msidata->bcb.message.payload.id > msidata->bcb.lastid) { |
||
996 | aosDbgPrintf("ok\n");
|
||
997 | // restart timeout timer
|
||
998 | chVTSet(&msidata->timeout.timer, chTimeUS2I(AOS_SSSP_TIMEOUT), _timerCallback, &msidata->timeout.eventsource); |
||
999 | // store ID
|
||
1000 | msidata->bcb.lastid = msidata->bcb.message.payload.id; |
||
1001 | } else {
|
||
1002 | aosDbgPrintf("fail\t->abort\n");
|
||
1003 | // initiate abortion
|
||
1004 | aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_4_ABORTION_INIT; |
||
1005 | } |
||
1006 | break;
|
||
1007 | } |
||
1008 | // abort message
|
||
1009 | case AOS_SSSP_BCBMESSAGE_MSIABORT:
|
||
1010 | { |
||
1011 | aosDbgPrintf("ABORT\tS-\t->sync\n");
|
||
1012 | // reset timeout timer
|
||
1013 | chVTReset(&msidata->timeout.timer); |
||
1014 | // deactivate S
|
||
1015 | apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_OFF); |
||
1016 | // proceed to abort synchronization
|
||
1017 | aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_4_ABORTION_SYNC; |
||
1018 | break;
|
||
1019 | } |
||
1020 | // invalid message
|
||
1021 | default:
|
||
1022 | { |
||
1023 | aosDbgPrintf("invalid\t->abort\n");
|
||
1024 | // initiate abortion
|
||
1025 | aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_4_ABORTION_INIT; |
||
1026 | break;
|
||
1027 | } |
||
1028 | } |
||
1029 | return;
|
||
1030 | } |
||
1031 | |||
1032 | /* INVALID BCB MESSAGE
|
||
1033 | * An obviously invalid message was received via BCB.
|
||
1034 | */
|
||
1035 | case AOS_SSSP_BCB_INVALIDMSG:
|
||
1036 | { |
||
1037 | // error but ignore
|
||
1038 | aosDbgPrintf("WARNING: unknown message received via BCB\n");
|
||
1039 | break;
|
||
1040 | } |
||
1041 | |||
1042 | /* NO BCB MESSAGE
|
||
1043 | * No message was received via BCB at all.
|
||
1044 | */
|
||
1045 | case AOS_SSSP_BCB_ERROR:
|
||
1046 | { |
||
1047 | // do nothing and proceed
|
||
1048 | break;
|
||
1049 | } |
||
1050 | } |
||
1051 | |||
1052 | /*
|
||
1053 | * handle events
|
||
1054 | */
|
||
1055 | *received = chEvtWaitOneTimeout(ALL_EVENTS, TIME_IMMEDIATE); |
||
1056 | /* TIMEOUT EVENT
|
||
1057 | * Timeouts can occur at any time during MSI after they have been initialized.
|
||
1058 | * As soon as the module has made it to the 3.4 completion stage, there will be no more timeouts, though.
|
||
1059 | */
|
||
1060 | if (*received & msidata->timeout.eventlistener.events) {
|
||
1061 | aosDbgPrintf("%u\ttimeout\t", chVTGetSystemTime());
|
||
1062 | // special cases
|
||
1063 | if (aos.sssp.stage == AOS_SSSP_STAGE_STARTUP_3_1_WAITFORINIT ||
|
||
1064 | aos.sssp.stage == AOS_SSSP_STAGE_STARTUP_3_4_COMPLETION) { |
||
1065 | // master did not initiate the sequence
|
||
1066 | if (aos.sssp.stage == AOS_SSSP_STAGE_STARTUP_3_1_WAITFORINIT) {
|
||
1067 | aosDbgPrintf("no init\t->operation\n");
|
||
1068 | // invalidate module ID
|
||
1069 | aos.sssp.moduleId = AOS_SSSP_MODULEID_INVALID; |
||
1070 | aosDbgPrintf("<<< MSI skipped\n");
|
||
1071 | } |
||
1072 | // no abort messages received after completion
|
||
1073 | else /* if (aos.sssp.stage == AOS_SSSP_STAGE_STARTUP_3_4_COMPLETION) */ { |
||
1074 | aosDbgPrintf("success\t->operation\n");
|
||
1075 | aosDbgPrintf("<<< MSI completed\n");
|
||
1076 | } |
||
1077 | // cleanup and proceed to operation phase
|
||
1078 | _msiOutro(msidata); |
||
1079 | } |
||
1080 | // general timeout
|
||
1081 | else {
|
||
1082 | aosDbgPrintf("->abort\n");
|
||
1083 | // initiate active abort
|
||
1084 | aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_4_ABORTION_INIT; |
||
1085 | } |
||
1086 | // clear event
|
||
1087 | chEvtGetAndClearFlags(&msidata->timeout.eventlistener); |
||
1088 | *received &= ~(msidata->timeout.eventlistener.events); |
||
1089 | } |
||
1090 | /* DELAY EVENT
|
||
1091 | * Delays are only used to toggle the UP signal.
|
||
1092 | */
|
||
1093 | else if (*received & _delayEventListener.events) { |
||
1094 | aosDbgPrintf("%u\tdelay\t", chVTGetSystemTime());
|
||
1095 | #if (AMIROOS_CFG_SSSP_STACK_END == true) |
||
1096 | apalControlGpioState_t s; |
||
1097 | aosDbgPrintf("S-\t");
|
||
1098 | // deactivate S
|
||
1099 | apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_OFF); |
||
1100 | // verify deactivation
|
||
1101 | apalControlGpioGet(moduleSsspSignalS(), &s); |
||
1102 | if (s == APAL_GPIO_OFF) {
|
||
1103 | aosDbgPrintf("ok\t->done\n");
|
||
1104 | // set the timeout timer so no abort messages are missed
|
||
1105 | chVTSet(&msidata->timeout.timer, chTimeUS2I(AOS_SSSP_TIMEOUT), _timerCallback, &msidata->timeout.eventsource); |
||
1106 | // proceed to the completion stage
|
||
1107 | aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_4_COMPLETION; |
||
1108 | } else {
|
||
1109 | aosDbgPrintf("fail\t->abort\n");
|
||
1110 | // initiate active abort
|
||
1111 | aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_4_ABORTION_INIT; |
||
1112 | } |
||
1113 | #else /* (AMIROOS_CFG_SSSP_STACK_END == true) */ |
||
1114 | apalControlGpioState_t s; |
||
1115 | // read the current state of the UP signal
|
||
1116 | apalControlGpioGet(moduleSsspSignalUP(), &s); |
||
1117 | if (s == APAL_GPIO_OFF) {
|
||
1118 | aosDbgPrintf("UP+ & S-\n");
|
||
1119 | // activate UP in order to trigger the next module
|
||
1120 | apalControlGpioSet(moduleSsspSignalUP(), APAL_GPIO_ON); |
||
1121 | // deactivate S
|
||
1122 | apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_OFF); |
||
1123 | // set the delay timer so the UP signal will get deactivated again later
|
||
1124 | chVTSet(&_delayTimer, chTimeUS2I(AOS_SSSP_DELAY), _timerCallback, &_delayEventSource); |
||
1125 | } else {
|
||
1126 | aosDbgPrintf("UP-\n");
|
||
1127 | // deactvate UP
|
||
1128 | apalControlGpioSet(moduleSsspSignalUP(), APAL_GPIO_OFF); |
||
1129 | } |
||
1130 | #endif /* (AMIROOS_CFG_SSSP_STACK_END == true) */ |
||
1131 | // clear event
|
||
1132 | chEvtGetAndClearFlags(&_delayEventListener); |
||
1133 | *received &= ~(_delayEventListener.events); |
||
1134 | } |
||
1135 | /* GPIO EVENT
|
||
1136 | * GPIO events can occurr at any time, but only DN and S events are expected.
|
||
1137 | * DN may be activated only once per module to trigger the counting process and is deactivated briefly after activation.
|
||
1138 | * S must only deactivate when MSI is comleted by the last module in the stack.
|
||
1139 | */
|
||
1140 | else if (*received & msidata->signals.eventlistener->events) { |
||
1141 | aosDbgPrintf("%u\tGPIO\t", chVTGetSystemTime());
|
||
1142 | apalControlGpioState_t s; |
||
1143 | // fetch event flags
|
||
1144 | eventflags_t flags = chEvtGetAndClearFlags(msidata->signals.eventlistener); |
||
1145 | #if (AMIROOS_CFG_SSSP_STACK_START != true) |
||
1146 | // if the DN signal was triggered
|
||
1147 | if (flags & moduleSsspEventflagDN()) {
|
||
1148 | // read the signal state
|
||
1149 | apalControlGpioGet(moduleSsspSignalDN(), &s); |
||
1150 | // rising edge
|
||
1151 | if (s == APAL_GPIO_ON) {
|
||
1152 | aosDbgPrintf("+DN\t");
|
||
1153 | // Correct SSSP stage and no ID assigned yet?
|
||
1154 | if (aos.sssp.stage == AOS_SSSP_STAGE_STARTUP_3_3_WAIT4EVENT &&
|
||
1155 | aos.sssp.moduleId == AOS_SSSP_MODULEID_INVALID) { |
||
1156 | // set the own module ID
|
||
1157 | aos.sssp.moduleId = msidata->bcb.lastid + 1;
|
||
1158 | aosDbgPrintf("set ID (%u)\t->bc ID\n", aos.sssp.moduleId);
|
||
1159 | // proceed to broadcasting
|
||
1160 | aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_3_BROADCASTID; |
||
1161 | } |
||
1162 | // incorrect SSSP stage or ID already assigned (triggered for a second time)
|
||
1163 | else {
|
||
1164 | aosDbgPrintf("->abort\n");
|
||
1165 | // initiate active abort
|
||
1166 | aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_4_ABORTION_INIT; |
||
1167 | } |
||
1168 | } |
||
1169 | // falling egde
|
||
1170 | else {
|
||
1171 | aosDbgPrintf("-DN\n");
|
||
1172 | // ignored
|
||
1173 | } |
||
1174 | // clear DN flags
|
||
1175 | flags &= ~moduleSsspEventflagDN(); |
||
1176 | } |
||
1177 | #endif /* (AMIROOS_CFG_SSSP_STACK_START != true) */ |
||
1178 | #if (AMIROOS_CFG_SSSP_STACK_END != true) |
||
1179 | // if the UP signal was triggered
|
||
1180 | if (flags & moduleSsspEventflagUP()) {
|
||
1181 | /*
|
||
1182 | * The UP signal is acting as output only.
|
||
1183 | * Any events resulting from toggling the signal are thus ignored.
|
||
1184 | */
|
||
1185 | aosDbgPrintf("?UP\n");
|
||
1186 | // clear UP flags
|
||
1187 | flags &= ~moduleSsspEventflagUP(); |
||
1188 | } |
||
1189 | #endif /* (AMIROOS_CFG_SSSP_STACK_END != true) */ |
||
1190 | // if the S signal was triggered
|
||
1191 | if (flags & moduleSsspEventflagS()) {
|
||
1192 | // read the signal state
|
||
1193 | apalControlGpioGet(moduleSsspSignalS(), &s); |
||
1194 | // rising edge
|
||
1195 | if (s == APAL_GPIO_ON) {
|
||
1196 | aosDbgPrintf("+S\n");
|
||
1197 | // ignored
|
||
1198 | } |
||
1199 | // falling edge
|
||
1200 | else {
|
||
1201 | aosDbgPrintf("-S\t");
|
||
1202 | // special case
|
||
1203 | if (aos.sssp.stage == AOS_SSSP_STAGE_STARTUP_3_4_ABORTION_SYNC) {
|
||
1204 | aosDbgPrintf("->operation\n");
|
||
1205 | // invalidate module ID
|
||
1206 | aos.sssp.moduleId = AOS_SSSP_MODULEID_INVALID; |
||
1207 | // proceed
|
||
1208 | aosDbgPrintf("<<< MSI aborted\n");
|
||
1209 | _msiOutro(msidata); |
||
1210 | } |
||
1211 | #if (AMIROOS_CFG_SSSP_STACK_END == true) |
||
1212 | // Correct SSSP stage?
|
||
1213 | else if (aos.sssp.stage == AOS_SSSP_STAGE_STARTUP_3_4_COMPLETION) { |
||
1214 | aosDbgPrintf("ok\n");
|
||
1215 | // ignored
|
||
1216 | } else {
|
||
1217 | aosDbgPrintf("->abort\n");
|
||
1218 | // initialize abortion
|
||
1219 | aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_4_ABORTION_INIT; |
||
1220 | } |
||
1221 | #else /* (AMIROOS_CFG_SSSP_STACK_END == true) */ |
||
1222 | // Correct SSSP stage and ID assigned?
|
||
1223 | else if (aos.sssp.stage == AOS_SSSP_STAGE_STARTUP_3_3_WAIT4EVENT && |
||
1224 | aos.sssp.moduleId != AOS_SSSP_MODULEID_INVALID) { |
||
1225 | aosDbgPrintf("->done\n");
|
||
1226 | // set the timeout timer so no abort messages are missed
|
||
1227 | chVTSet(&msidata->timeout.timer, chTimeUS2I(AOS_SSSP_TIMEOUT), _timerCallback, &msidata->timeout.eventsource); |
||
1228 | // proceed to the completion stage
|
||
1229 | aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_4_COMPLETION; |
||
1230 | } else {
|
||
1231 | aosDbgPrintf("->abort\n");
|
||
1232 | // initiate abortion
|
||
1233 | aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_4_ABORTION_INIT; |
||
1234 | } |
||
1235 | #endif /* (AMIROOS_CFG_SSSP_STACK_END == true) */ |
||
1236 | } |
||
1237 | // clear S flags
|
||
1238 | flags &= ~moduleSsspEventflagS(); |
||
1239 | } |
||
1240 | // any further flags set?
|
||
1241 | if (flags) {
|
||
1242 | aosDbgPrintf("0x%08X\n", flags);
|
||
1243 | // reassign remaining flags and do not clear event mask
|
||
1244 | msidata->signals.eventlistener->flags |= flags; |
||
1245 | } else {
|
||
1246 | // clear event
|
||
1247 | *received &= ~(msidata->signals.eventlistener->events); |
||
1248 | } |
||
1249 | } |
||
1250 | /* OTHER EVENT
|
||
1251 | * Any other events may occur as well but are not handled by this function
|
||
1252 | */
|
||
1253 | else if (*received != 0){ |
||
1254 | aosDbgPrintf("%u\tOTHER\t0x%08X\n", chVTGetSystemTime(), *received);
|
||
1255 | // do not clear the event mask
|
||
1256 | } |
||
1257 | |||
1258 | return;
|
||
1259 | } |
||
1260 | |||
1261 | #endif /* (AMIROOS_CFG_SSSP_MSI == true) */ |
||
1262 | |||
1263 | #if ((AMIROOS_CFG_SSSP_MASTER != true) && (AMIROOS_CFG_PROFILE == true)) || defined(__DOXYGEN__) |
||
1264 | |||
1265 | /**
|
||
1266 | a93a1019 | Thomas Schöpping | * @brief Retrieve the offset between local clock and system synchronization signal.
|
1267 | c53ef0b1 | Thomas Schöpping | *
|
1268 | * @return
|
||
1269 | */
|
||
1270 | inline float aosSsspGetSyncSkew(void) |
||
1271 | { |
||
1272 | return _syncskew;
|
||
1273 | } |
||
1274 | |||
1275 | #endif /* (AMIROOS_CFG_SSSP_MASTER != true) && (AMIROOS_CFG_PROFILE == true) */ |
||
1276 | |||
1277 | c218345a | Thomas Schöpping | /**
|
1278 | * @brief Leave the operation pahse and initiate or acknowledge shutdown.
|
||
1279 | *
|
||
1280 | * @param[in] active Flag, indicating whether the shutdon shall be activeliy initiated (true) or a passive request was received (false).
|
||
1281 | */
|
||
1282 | void aosSsspShutdownInit(bool active) |
||
1283 | cda14729 | Thomas Schöpping | { |
1284 | c218345a | Thomas Schöpping | aosDbgAssert(aos.sssp.stage == AOS_SSSP_STAGE_OPERATION); |
1285 | |||
1286 | cda14729 | Thomas Schöpping | // proceed to shutdown phase
|
1287 | c218345a | Thomas Schöpping | aos.sssp.stage = AOS_SSSP_STAGE_SHUTDOWN_1_1; |
1288 | |||
1289 | // activate PD if this was an active shutdown initiation
|
||
1290 | if (active) {
|
||
1291 | c53ef0b1 | Thomas Schöpping | apalControlGpioSet(moduleSsspSignalPD(), APAL_GPIO_ON); |
1292 | c218345a | Thomas Schöpping | } |
1293 | |||
1294 | #if (AMIROOS_CFG_SSSP_MASTER == true) |
||
1295 | // stop toggling S
|
||
1296 | chVTReset(&_synctimer); |
||
1297 | #endif /* (AMIROOS_CFG_SSSP_MASTER == true) */ |
||
1298 | |||
1299 | // activate S
|
||
1300 | c53ef0b1 | Thomas Schöpping | apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_ON); |
1301 | c218345a | Thomas Schöpping | |
1302 | // proceed in the shutdown phase
|
||
1303 | cda14729 | Thomas Schöpping | aos.sssp.stage = AOS_SSSP_STAGE_SHUTDOWN_1_2; |
1304 | |||
1305 | return;
|
||
1306 | } |
||
1307 | |||
1308 | #if (AMIROOS_CFG_SSSP_SHUTDOWN == true) || defined(__DOXYGEN__) |
||
1309 | |||
1310 | /**
|
||
1311 | * @brief Sequnetially broadcast an identifier via S to specify a specific way to shutdown or restart.
|
||
1312 | *
|
||
1313 | * @param[in] identifier Identifier to be broadcasted.
|
||
1314 | */
|
||
1315 | void aosSsspShutdownBroadcastIdentifier(unsigned int identifier) |
||
1316 | { |
||
1317 | // only broadcast anything if a identifier greater than 0 was specified
|
||
1318 | if (identifier > 0) { |
||
1319 | // broadcast identifier
|
||
1320 | for (unsigned int pulse = 0; pulse < identifier; ++pulse) { |
||
1321 | // wait one delay time with S being deactivated
|
||
1322 | aosThdUSleep(AOS_SSSP_DELAY); |
||
1323 | |||
1324 | // activate S for one AOS_SSSP_DELAY.
|
||
1325 | c53ef0b1 | Thomas Schöpping | apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_ON); |
1326 | cda14729 | Thomas Schöpping | aosThdUSleep(AOS_SSSP_DELAY); |
1327 | c53ef0b1 | Thomas Schöpping | apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_OFF); |
1328 | cda14729 | Thomas Schöpping | } |
1329 | } |
||
1330 | |||
1331 | // let a timeout pass and return
|
||
1332 | aosThdUSleep(AOS_SSSP_TIMEOUT); |
||
1333 | |||
1334 | return;
|
||
1335 | } |
||
1336 | |||
1337 | /**
|
||
1338 | * @brief Wait for a pulse during the SSSP shutdown disambiguation procedure.
|
||
1339 | * @details Whenever a pulse is received, the identifier is incremented.
|
||
1340 | * Otherwise the internal timer is configured and will eventually trigger a timeout event.
|
||
1341 | *
|
||
1342 | * @param[in] gpiolistener Event listener for GPIO events.
|
||
1343 | * @param[in] sflags Event flags to be set by edges on the S signal.
|
||
1344 | * @param[in] timermask Event maks to use for the internal timer.
|
||
1345 | * @param[in,out] identifier Identifier variable to increment.
|
||
1346 | *
|
||
1347 | * @return The event mask of whatever event was received during this function call.
|
||
1348 | */
|
||
1349 | eventmask_t aosSsspShutdownWaitForIdentifierPulse(event_listener_t* gpiolistener, const eventflags_t sflags, eventmask_t timermask, unsigned int* identifier) |
||
1350 | { |
||
1351 | aosDbgCheck(gpiolistener != NULL);
|
||
1352 | aosDbgCheck(sflags != 0);
|
||
1353 | aosDbgCheck(timermask != 0);
|
||
1354 | aosDbgCheck(identifier != NULL);
|
||
1355 | |||
1356 | // local variables
|
||
1357 | eventmask_t mask; |
||
1358 | eventflags_t flags; |
||
1359 | apalControlGpioState_t sstate; |
||
1360 | |||
1361 | // arm the timer once
|
||
1362 | if (!chVTIsArmed(&_delayTimer)) {
|
||
1363 | c53ef0b1 | Thomas Schöpping | chEvtRegisterMask(&_delayEventSource, &_delayEventListener, timermask); |
1364 | chVtSet(&_delayTimer, chTimeUS2I(AOS_SSSP_TIMEOUT), _timerCallback, &_delayEventSource); |
||
1365 | cda14729 | Thomas Schöpping | } |
1366 | |||
1367 | // wait for any event to occur (do not apply any filters in order not to miss any events)
|
||
1368 | mask = chEvtWaitOne(ALL_EVENTS); |
||
1369 | |||
1370 | // GPIO event
|
||
1371 | if (mask & gpiolistener->events) {
|
||
1372 | a93a1019 | Thomas Schöpping | // retrieve flags without clearing them
|
1373 | cda14729 | Thomas Schöpping | flags = gpiolistener->flags; |
1374 | c53ef0b1 | Thomas Schöpping | apalControlGpioGet(moduleSsspSignalS(), &sstate); |
1375 | cda14729 | Thomas Schöpping | if (flags == sflags) {
|
1376 | c53ef0b1 | Thomas Schöpping | apalControlGpioGet(moduleSsspSignalS(), &sstate); |
1377 | cda14729 | Thomas Schöpping | // if this was the end of a pulse
|
1378 | if (sstate == APAL_GPIO_OFF) {
|
||
1379 | // restart the timer
|
||
1380 | c53ef0b1 | Thomas Schöpping | chVtSet(&_delayTimer, chTimeUS2I(AOS_SSSP_TIMEOUT), _timerCallback, &_delayEventSource); |
1381 | cda14729 | Thomas Schöpping | // increment the identifier
|
1382 | ++(*identifier); |
||
1383 | } |
||
1384 | } |
||
1385 | } |
||
1386 | // timer event
|
||
1387 | c53ef0b1 | Thomas Schöpping | else if (mask & _delayEventListener.events) { |
1388 | cda14729 | Thomas Schöpping | // unregister event
|
1389 | c53ef0b1 | Thomas Schöpping | chEvtUnregister(&_delayEventSource, &_delayEventListener); |
1390 | cda14729 | Thomas Schöpping | } |
1391 | // any further events must be handled externally
|
||
1392 | |||
1393 | return mask;
|
||
1394 | } |
||
1395 | |||
1396 | #endif /* (AMIROOS_CFG_SSSP_SHUTDOWN == true) */ |
||
1397 | |||
1398 | #endif /* (AMIROOS_CFG_SSSP_ENABLE == true) */ |
||
1399 | |||
1400 | /** @} */ |