Statistics
| Branch: | Tag: | Revision:

amiro-os / core / src / aos_main.cpp @ 8376530c

History | View | Annotate | Download (43.012 KB)

1
/*
2
AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
3
Copyright (C) 2016..2018  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_main.cpp
21
 * @brief   Main function.
22
 * @details Main function with SSSP and initialization,
23
 *          extendable via hooks.
24
 *
25
 * @addtogroup aos_system
26
 * @{
27
 */
28

    
29
#include <amiroos.h>
30
#include <module.h>
31

    
32
/*
33
 * hook to add further includes
34
 */
35
#if defined(AMIROOS_CFG_MAIN_EXTRA_INCLUDE_HEADER)
36
#include AMIROOS_CFG_MAIN_EXTRA_INCLUDE_HEADER
37
#endif
38

    
39
/**
40
 * @brief   Event mask to identify I/O events.
41
 */
42
#define IOEVENT_MASK                            EVENT_MASK(0)
43

    
44
/**
45
 * @brief   Event mask to identify OS events.
46
 */
47
#define OSEVENT_MASK                            EVENT_MASK(1)
48

    
49
/**
50
 * @brief   Event mask to idetify CAN events.
51
 */
52
#define CANEVENT_MASK                           EVENT_MASK(2)
53

    
54
/**
55
 * @brief   Event mask to idetify timeout events.
56
 */
57
#define TIMEOUTEVENT_MASK                       EVENT_MASK(3)
58

    
59
/**
60
 * @brief   Event mask to idetify signal delay events.
61
 */
62
#define DELAYEVENT_MASK                         EVENT_MASK(4)
63

    
64
/**
65
 * @brief   CAN message identifier for initialization of the SSSP stack initialization sequence.
66
 */
67
#define SSSP_STACKINIT_CANMSGID_INIT            0x003
68

    
69
/**
70
 * @brief   CAN message identifier for transmitting module IDs during the SSSP stack initialization sequence.
71
 */
72
#define SSSP_STACKINIT_CANMSGID_MODULEID        0x002
73

    
74
/**
75
 * @brief   CAN message identifier for abortion of the SSSP stack initialization sequence.
76
 */
77
#define SSSP_STACKINIT_CANMSGID_ABORT           0x001
78

    
79
/**
80
 * @brief   CAN message identifier for calender synchronization message.
81
 */
82
#define CALENDERSYNC_CANMSGID                   0x004
83

    
84
/**
85
 * @brief   Listener object for I/O events.
86
 */
87
static event_listener_t _eventListenerIO;
88

    
89
/**
90
 * @brief   Listener object for OS events.
91
 */
92
static event_listener_t _eventListenerOS;
93

    
94
#if defined(MODULE_HAL_PROGIF) || defined(__DOXYGEN__)
95
/**
96
 * @brief   I/O channel for the programmer interface.
97
 */
98
static AosIOChannel _stdiochannel;
99

    
100
#if (AMIROOS_CFG_SHELL_ENABLE == true) || defined(__DOXYGEN__)
101
/**
102
 * @brief   I/O shell channel for the programmer interface.
103
 */
104
static AosShellChannel _stdshellchannel;
105
#endif
106
#endif
107

    
108
/*
109
 * hook to add further static variables
110
 */
111
#if defined(AMIROOS_CFG_MAIN_EXTRA_STATIC_VARIABLES)
112
AMIROOS_CFG_MAIN_EXTRA_STATIC_VARIABLES
113
#endif
114

    
115
/**
116
 * @brief   Prints an error message about an unexpected event.
117
 *
118
 * @param[in] mask    The event mask.
119
 * @param[in] flags   The event flags.
120
 */
121
static inline void _unexpectedEventError(const eventmask_t mask, const eventflags_t flags)
122
{
123
#if (AMIROOS_CFG_DBG == true)
124
  aosprintf("CTRL: unexpected/unknown event received. mask: 0x%08X; flags: 0x%08X\n", mask, flags);
125
#else
126
  (void)(mask);
127
  (void)(flags);
128
#endif
129
  return;
130
}
131

    
132
/**
133
 * @brief   Callback function to be used during SSSP stack initialization sequence.
134
 *
135
 * @param[in] par   A pointer to an @p event_source_t to be fired.
136
 */
137
static void _ssspTimerCallback(void* par)
138
{
139
  aosDbgCheck(par != NULL);
140

    
141
  chSysLockFromISR();
142
  chEvtBroadcastI((event_source_t*)par);
143
  chSysUnlockFromISR();
144

    
145
  return;
146
}
147

    
148
/**
149
 * @brief   Helper function to serialize data.
150
 *
151
 * @param[out]  dst   Pointer to the output buffer.
152
 * @param[in]   src   Data to be serialized.
153
 * @param[in]   n     Number of bytes to serialize.
154
 */
155
inline void _serialize(uint8_t* dst, const uint64_t src, const uint8_t n)
156
{
157
  aosDbgCheck(dst != NULL);
158
  aosDbgCheck(n > 0 && n <= 8);
159

    
160
  for (uint8_t byte = 0; byte < n; ++byte) {
161
    dst[byte] = (uint8_t)((src >> (byte * 8)) & 0xFF);
162
  }
163

    
164
  return;
165
}
166

    
167
/**
168
 * @brief   Helper function to deserialize data.
169
 *
170
 * @param[in] src   Pointer to the buffer of data to be deserialzed.
171
 * @param[in] n     Number of bytes to deserialize.
172
 *
173
 * @return    The deserialized 32 bit data.
174
 */
175
inline uint64_t _deserialize(uint8_t* src, const uint8_t n)
176
{
177
  aosDbgCheck(src != NULL);
178
  aosDbgCheck(n > 0 && n <= 8);
179

    
180
  uint64_t result = 0;
181
  for (uint8_t byte = 0; byte < n; ++byte) {
182
    result |= ((uint64_t)src[byte]) << (byte * 8);
183
  }
184

    
185
  return result;
186
}
187

    
188
/**
189
 * @brief   Converter function to encode a TM value to a single unsigned 64 bit integer.
190
 *
191
 * @details Contents of the TM struct are mapped as follows:
192
 *            bits  |63     62|61      53|52    50|49         26|25     22|21     17|16     12|11      6|5       0|
193
 *            #bits |       2 |        9 |      3 |          24 |       4 |       5 |       5 |       6 |       6 |
194
 *            value |   isdst |     yday |   wday |        year |     mon |    mday |    hour |     min |     sec |
195
 *            range | special | [0, 365] | [0, 6] | [1900, ...] | [0, 11] | [1, 31] | [0, 23] | [0, 59] | [0, 61] |
196
 *          The Daylight Saving Time Flag (isdsst) is encoded as follows:
197
 *            DST not in effect         -> 0
198
 *            DST in effect             -> 1
199
 *            no information available  -> 2
200
 *
201
 * @param[in] src   Pointer to the TM struct to encode.
202
 *
203
 * @return  An unsigned 64 bit integer, which holds the encoded time value.
204
 */
205
inline uint64_t _TM2U64(struct tm* src)
206
{
207
  aosDbgCheck(src != NULL);
208

    
209
  return (((uint64_t)(src->tm_sec  & 0x0000003F) << (0))               |
210
          ((uint64_t)(src->tm_min  & 0x0000003F) << (6))               |
211
          ((uint64_t)(src->tm_hour & 0x0000001F) << (12))              |
212
          ((uint64_t)(src->tm_mday & 0x0000001F) << (17))              |
213
          ((uint64_t)(src->tm_mon  & 0x0000000F) << (22))              |
214
          ((uint64_t)(src->tm_year & 0x00FFFFFF) << (26))              |
215
          ((uint64_t)(src->tm_wday & 0x00000007) << (50))              |
216
          ((uint64_t)(src->tm_yday & 0x000001FF) << (53))              |
217
          ((uint64_t)((src->tm_isdst == 0) ? 0 : (src->tm_isdst > 0) ? 1 : 2) << (62)));
218
}
219

    
220
/**
221
 * @brief   Converter functiomn to retrieve the encoded TM value from an unsigned 64 bit integer.
222
 *
223
 * @details For information on the encoding, please refer to @p _TM2U64 function.
224
 *
225
 * @param[out] dst  The TM struct to fill with the decoded values.
226
 * @param[in]  src  Unsigned 64 bit integer holding the encoded TM value.
227
 */
228
inline void _U642TM(struct tm* dst, const uint64_t src)
229
{
230
  aosDbgCheck(dst != NULL);
231

    
232
  dst->tm_sec  = (src >> 0)  & 0x0000003F;
233
  dst->tm_min  = (src >> 6)  & 0x0000003F;
234
  dst->tm_hour = (src >> 12) & 0x0000001F;
235
  dst->tm_mday = (src >> 17) & 0x0000001F;
236
  dst->tm_mon  = (src >> 22) & 0x0000000F;
237
  dst->tm_year = (src >> 26) & 0x00FFFFFF;
238
  dst->tm_wday = (src >> 50) & 0x00000007;
239
  dst->tm_yday = (src >> 53) & 0x000001FF;
240
  dst->tm_isdst = (((src >> 62) & 0x03) == 0) ? 0 : (((src >> 62) & 0x03) > 0) ? 1 : -1;
241

    
242
  return;
243
}
244

    
245
/**
246
 * @brief   Implementation of the SSSP module stack initialization sequence (startup phase 3).
247
 *
248
 * @return Shutdown value.
249
 * @retval AOS_SHUTDOWN_NONE      No shutdown signal received
250
 * @retval AOS_SHUTDOWN_PASSIVE   Shutdown signal received.
251
 */
252
aos_shutdown_t _ssspModuleStackInitialization(void)
253
{
254
  // local types
255
  /**
256
   * @brief   States for the internal state machine to implement SSSP startup stage 3.
257
   */
258
  typedef enum {
259
    STAGE_3_1,                  /**< Initiation of SSSP startup stage 3. */
260
    STAGE_3_2,                  /**< Starting the sequence and broadcasting the first ID. */
261
    STAGE_3_3_WAITFORFIRSTID,   /**< Waiting for first ID after initiation. */
262
    STAGE_3_3_WAITFORIDORSIG,   /**< Waiting for next ID or activation of neighbor signal. */
263
    STAGE_3_3_WAITFORID,        /**< Waiting for next ID (after the module has set its own ID). */
264
    STAGE_3_4_FINISH,           /**< Successful finish of stage 3. */
265
    STAGE_3_4_ABORT_ACTIVE,     /**< Aborting stage 3 (active). */
266
    STAGE_3_4_ABORT,            /**< Aborting stage 3 (passive). */
267
  } sssp_modulestackinitstage_t;
268

    
269
  typedef struct {
270
    bool loop     : 1;
271
    bool wfe      : 1;
272
    bool wfe_next : 1;
273
  } flags_t;
274

    
275
  // local variables
276
  aos_shutdown_t shutdown = AOS_SHUTDOWN_NONE;
277
  sssp_modulestackinitstage_t stage = STAGE_3_1;
278
  eventmask_t eventmask = 0;
279
  eventflags_t ioflags;
280
  event_source_t eventSourceTimeout;
281
  event_source_t eventSourceDelay;
282
  event_listener_t eventListenerTimeout;
283
  event_listener_t eventListenerDelay;
284
  event_listener_t eventListenerCan;
285
  virtual_timer_t timerTimeout;
286
  virtual_timer_t timerDelay;
287
  CANTxFrame canTxFrame;
288
  CANRxFrame canRxFrame;
289
#if (AMIROOS_CFG_SSSP_STACK_START != true) || (AMIROOS_CFG_DBG == true)
290
  aos_ssspmoduleid_t lastid = 0;
291
#endif
292
  flags_t flags;
293

    
294
  // initialize local varibles
295
  chEvtObjectInit(&eventSourceTimeout);
296
  chEvtObjectInit(&eventSourceDelay);
297
  chVTObjectInit(&timerTimeout);
298
  chVTObjectInit(&timerDelay);
299
  canTxFrame.RTR = CAN_RTR_DATA;
300
  canTxFrame.IDE = CAN_IDE_STD;
301
  flags.loop = true;
302
  flags.wfe = false; // do not wait for events in the initial iteration of the FSM loop
303
  flags.wfe_next = true;
304

    
305
  // initialize system variables
306
  aos.sssp.stage = AOS_SSSP_STARTUP_3_1;
307
  aos.sssp.moduleId = 0;
308

    
309
  // listen to events (timout, delay, CAN receive)
310
  chEvtRegisterMask(&eventSourceTimeout, &eventListenerTimeout, TIMEOUTEVENT_MASK);
311
  chEvtRegisterMask(&eventSourceDelay, &eventListenerDelay, DELAYEVENT_MASK);
312
  chEvtRegisterMask(&MODULE_HAL_CAN.rxfull_event, &eventListenerCan, CANEVENT_MASK);
313

    
314
  /*
315
   * FSM in a loop.
316
   *
317
   * This is a fully event-based FSM for the module stack initialization
318
   * sequence, defined by SSSP as startup stage 3. There are five different
319
   * events that can occur at this point:
320
   *  I/O events: The input level of an input pin has changed. Such events must
321
   *              be handled differently depending on the current state. Most
322
   *              of the time, however, such events can be ignored.
323
   *  OS events:  Such events are only available after this stage completed and
324
   *              thus should never occur. However, there is an optional hook
325
   *              to handle such events, nevertheless.
326
   *  CAN events: At least one CAN message was received. Note that this event
327
   *              will only fire again if all input buffers have been cleared.
328
   *  timeouts:   If some module does not support the sequence of there is any
329
   *              issue, such a case is detected via timeouts and must be
330
   *              handled accordingly (see abort state). In some cases, it is
331
   *              possible that a timeout event occurres 'simultaneously' with
332
   *              some other event. This can be caused by several timing issues
333
   *              and is a valid situation. As a result, any other events
334
   *              should be handled before the timeout event. If the other
335
   *              events are expected and valid, this implementation requires
336
   *              the timeout event flag to be cleared explicitely. Otherwise
337
   *              it is evaluated at the end of each iteration of the loop.
338
   *  delays:     Depending on the current state, delays are required by SSSP
339
   *              for timing of the sequential activation of signals.
340
   */
341
  aosDbgPrintf("SSSP stack initialization sequence:\n");
342
  while (flags.loop) {
343
#if (AMIROOS_CFG_DBG == true)
344
    switch (stage) {
345
      case STAGE_3_1:
346
        aosDbgPrintf(">>> 3-1\n");
347
        break;
348
      case STAGE_3_2:
349
        aosDbgPrintf(">>> 3-2\n");
350
        break;
351
      case STAGE_3_3_WAITFORFIRSTID:
352
        aosDbgPrintf(">>> 3-3 (1st ID)\n");
353
        break;
354
      case STAGE_3_3_WAITFORIDORSIG:
355
        aosDbgPrintf(">>> 3-3 (ID/sig)\n");
356
        break;
357
      case STAGE_3_3_WAITFORID:
358
        aosDbgPrintf(">>> 3-3 (ID)\n");
359
        break;
360
      case STAGE_3_4_FINISH:
361
        aosDbgPrintf(">>> 3-4 (finish)\n");
362
        break;
363
      case STAGE_3_4_ABORT_ACTIVE:
364
        aosDbgPrintf(">>> 3-4 (active abort)\n");
365
        break;
366
      case STAGE_3_4_ABORT:
367
        aosDbgPrintf(">>> 3-4 (abort)\n");
368
        break;
369
    }
370
#endif
371

    
372
    // reset wfe flag for the next iteration
373
    flags.wfe_next = true;
374

    
375
    // waiting for events may be skipped
376
    if (flags.wfe) {
377
      // wait for any event to occur
378
      aosDbgPrintf("WFE...");
379
      eventmask = chEvtWaitAnyTimeout(ALL_EVENTS, chTimeUS2I(AOS_SYSTEM_SSSP_TIMEOUT));
380
      aosDbgPrintf("\t0x%08X", eventmask);
381
    } else {
382
      aosDbgPrintf("WFE skipped");
383
    }
384
    aos_timestamp_t uptime;
385
    aosSysGetUptime(&uptime);
386
    aosDbgPrintf("\t%04ums\n", (uint32_t)(uptime / 1000));
387

    
388
    /*
389
     * execute some general tasks and high priority events
390
     */
391
    // no event occurred at all
392
    if ((flags.wfe) && (eventmask == 0)) {
393
      aosDbgPrintf("ERR: no evt\n");
394
      // enforce timeout event
395
      chEvtBroadcast(&eventSourceTimeout);
396
      continue;
397
    }
398
    // if an IO event occurred
399
    if (eventmask & _eventListenerIO.events) {
400
      ioflags = chEvtGetAndClearFlags(&_eventListenerIO);
401
      aosDbgPrintf("INFO: IO evt (0x%08X)\n", ioflags);
402
      // a power-down event occurred
403
      if (ioflags & MODULE_SSSP_EVENTFLAGS_PD) {
404
        aosDbgPrintf("PD evt\n");
405
        // deactivate S and UP
406
        apalControlGpioSet(&moduleSsspGpioSync, APAL_GPIO_OFF);
407
  #if (AMIROOS_CFG_SSSP_STACK_END != true)
408
        apalControlGpioSet(&moduleSsspGpioUp, APAL_GPIO_OFF);
409
  #endif
410
        // set shutdown flag and exit the loop
411
        shutdown = AOS_SHUTDOWN_PASSIVE;
412
        break;
413
      }
414
      // the S signal was deactivated
415
      if (ioflags & MODULE_SSSP_EVENTFLAGS_SYNC) {
416
        apalControlGpioState_t sstate;
417
        apalControlGpioGet(&moduleSsspGpioSync, &sstate);
418
        if (sstate == APAL_GPIO_OFF) {
419
          aosDbgPrintf("-S evt\n");
420
          // either finish or abort
421
          if ((stage == STAGE_3_3_WAITFORID) && (aos.sssp.moduleId != 0)) {
422
            stage = STAGE_3_4_FINISH;
423
          } else if (stage != STAGE_3_4_ABORT) {
424
            stage = STAGE_3_4_ABORT_ACTIVE;
425
          }
426
        }
427
      }
428
    }
429
    // an OS event occurred
430
    if (eventmask & _eventListenerOS.events) {
431
      aosDbgPrintf("WARN: OS evt\n");
432
      // get the flags
433
      eventflags_t oseventflags = chEvtGetAndClearFlags(&_eventListenerOS);
434
      // there should be no OS events at this point
435
#ifdef MODULE_SSSP_STARTUP_3_OSEVENT_HOOK
436
      MODULE_SSSP_STARTUP_3_OSEVENT_HOOK(eventmask, eventflags);
437
#else
438
      _unexpectedEventError(eventmask, oseventflags);
439
#endif
440
    }
441
    // if a CAN event occurred
442
    if ((eventmask & eventListenerCan.events)) {
443
      // fetch message
444
      if (flags.wfe) {
445
        canReceiveTimeout(&MODULE_HAL_CAN, CAN_ANY_MAILBOX, &canRxFrame, TIME_IMMEDIATE);
446
        aosDbgPrintf("CAN <- 0x%03X\n", canRxFrame.SID);
447
      }
448
      // identify and handle abort messgaes
449
      if (canRxFrame.SID == SSSP_STACKINIT_CANMSGID_ABORT) {
450
        stage = STAGE_3_4_ABORT;
451
      }
452
      // warn if a unexpected message was received
453
      else if ((canRxFrame.SID != SSSP_STACKINIT_CANMSGID_INIT) &&
454
               (canRxFrame.SID != SSSP_STACKINIT_CANMSGID_MODULEID)) {
455
        aosDbgPrintf("WARN: unknown msg\n");
456
      }
457
      // any further pending messages are fetched at the end of the loop
458
    }
459
    // if a timeout event occurred
460
    if (eventmask & eventListenerTimeout.events) {
461
      // is handled at the end of the loop (or must be cleared by FSM)
462
    }
463
    // if a delay event occurred
464
    if (eventmask & eventListenerDelay.events) {
465
      // is handled by FSM
466
    }
467

    
468
    /*
469
     * this is the actual FSM
470
     */
471
    switch (stage) {
472
      case STAGE_3_1:
473
      {
474
        aos.sssp.stage = AOS_SSSP_STARTUP_3_1;
475

    
476
        // there was no event at all (skipped wfe)
477
        if (eventmask == 0 && flags.wfe == false) {
478
#if (AMIROOS_CFG_SSSP_MASTER == true)
479
          // initialize the stage by transmitting an according CAN message
480
          aosDbgPrintf("CAN -> init\n");
481
          canTxFrame.DLC = 0;
482
          canTxFrame.SID = SSSP_STACKINIT_CANMSGID_INIT;
483
          if (canTransmitTimeout(&MODULE_HAL_CAN, CAN_ANY_MAILBOX, &canTxFrame, TIME_IMMEDIATE) != MSG_OK) {
484
            chEvtBroadcast(&eventSourceTimeout);
485
            break;
486
          }
487
          // activate S
488
          aosDbgPrintf("S+\n");
489
          apalControlGpioSet(&moduleSsspGpioSync, APAL_GPIO_ON);
490
#if (AMIROOS_CFG_SSSP_STACK_START == true)
491
          // proceed immediately
492
          stage = STAGE_3_2;
493
          flags.wfe_next = false;
494
#else
495
          // set the timeout timer
496
          chVTSet(&timerTimeout, chTimeUS2I(AOS_SYSTEM_SSSP_TIMEOUT), _ssspTimerCallback, &eventSourceTimeout);
497
          // proceed
498
          stage = STAGE_3_3_WAITFORFIRSTID;
499
#endif
500
#else
501
          // set the timeout timer
502
          chVTSet(&timerTimeout, chTimeUS2I(AOS_SYSTEM_SSSP_TIMEOUT), _ssspTimerCallback, &eventSourceTimeout);
503
#endif
504
        }
505

    
506
#if (AMIROOS_CFG_SSSP_MASTER != true)
507
        // a CAN message was received
508
        else if (eventmask & eventListenerCan.events) {
509
          // if an initiation message was received
510
          if (canRxFrame.DLC == 0 &&
511
              canRxFrame.RTR == CAN_RTR_DATA &&
512
              canRxFrame.IDE == CAN_IDE_STD &&
513
              canRxFrame.SID == SSSP_STACKINIT_CANMSGID_INIT) {
514
            aosDbgPrintf("init msg\n");
515
            // reset the timeout timer and clear pending flags
516
            chVTReset(&timerTimeout);
517
            chEvtWaitAnyTimeout(eventListenerTimeout.events, TIME_IMMEDIATE);
518
            eventmask &= ~(eventListenerTimeout.events);
519
            // activate S
520
            aosDbgPrintf("S+\n");
521
            apalControlGpioSet(&moduleSsspGpioSync, APAL_GPIO_ON);
522
#if (AMIROOS_CFG_SSSP_STACK_START == true)
523
            // proceed
524
            stage = STAGE_3_2;
525
            flags.wfe_next = false;
526
#else
527
            // set the timeout timer
528
            chVTSet(&timerTimeout, chTimeUS2I(AOS_SYSTEM_SSSP_TIMEOUT), _ssspTimerCallback, &eventSourceTimeout);
529
            // proceed
530
            stage = STAGE_3_3_WAITFORFIRSTID;
531
#endif
532
          }
533
        }
534
#endif
535

    
536
        break;
537
      } /* end of STAGE_3_1 */
538

    
539
      case STAGE_3_2:
540
      {
541
#if (AMIROOS_CFG_SSSP_STACK_START == true)
542
        aos.sssp.stage = AOS_SSSP_STARTUP_3_2;
543

    
544
        // if this stage was just entered
545
        if (flags.wfe == false) {
546
          // set the module ID
547
          aos.sssp.moduleId = 1;
548
          // broadcast module ID
549
          aosDbgPrintf("CAN -> ID (%u)\n", aos.sssp.moduleId);
550
          canTxFrame.DLC = 4;
551
          canTxFrame.SID = SSSP_STACKINIT_CANMSGID_MODULEID;
552
          _serialize(canTxFrame.data8, aos.sssp.moduleId, 4);
553
          if (canTransmitTimeout(&MODULE_HAL_CAN, CAN_ANY_MAILBOX, &canTxFrame, TIME_IMMEDIATE) != MSG_OK) {
554
            chEvtBroadcast(&eventSourceTimeout);
555
            break;
556
          }
557
#if (AMIROOS_CFG_SSSP_STACK_START != true) || (AMIROOS_CFG_DBG == true)
558
          lastid = aos.sssp.moduleId;
559
#endif
560
#if (AMIROOS_CFG_SSSP_STACK_END == true)
561
          // sequence is already over
562
          // deactivate S
563
          aosDbgPrintf("S-\n");
564
          apalControlGpioSet(&moduleSsspGpioSync, APAL_GPIO_OFF);
565
          // proceed
566
          stage = STAGE_3_3_WAITFORID;
567
#else
568
          // set the delay timer so the UP signal is activated later
569
          chVTSet(&timerDelay, chTimeUS2I(AMIROOS_CFG_SSSP_SIGNALDELAY), _ssspTimerCallback, &eventSourceDelay);
570
#endif
571
        }
572

    
573
        // if a delay event occurred
574
        if (eventmask & eventListenerDelay.events) {
575
          // activate UP
576
          aosDbgPrintf("UP+\n");
577
          apalControlGpioSet(&moduleSsspGpioUp, APAL_GPIO_ON);
578
          // deactivate S
579
          aosDbgPrintf("S-\n");
580
          apalControlGpioSet(&moduleSsspGpioSync, APAL_GPIO_OFF);
581
          // explicitely clear timeout event flag
582
          chEvtWaitAnyTimeout(eventListenerTimeout.events, TIME_IMMEDIATE);
583
          eventmask &= ~(eventListenerTimeout.events);
584
          // proceed
585
          stage = STAGE_3_3_WAITFORID;
586
        }
587
#endif
588

    
589
        break;
590
      } /* end of STAGE_3_2 */
591

    
592
      case STAGE_3_3_WAITFORFIRSTID:
593
      {
594
#if (AMIROOS_CFG_SSSP_STACK_START != true)
595
        aos.sssp.stage = AOS_SSSP_STARTUP_3_3;
596

    
597
        // a CAN message was received
598
        if (eventmask & eventListenerCan.events) {
599
          // if an ID message was received
600
          if (canRxFrame.DLC == 4 &&
601
              canRxFrame.RTR == CAN_RTR_DATA &&
602
              canRxFrame.IDE == CAN_IDE_STD &&
603
              canRxFrame.SID == SSSP_STACKINIT_CANMSGID_MODULEID) {
604
            aosDbgPrintf("ID (%u)\n", (uint32_t)_deserialize(canRxFrame.data8, 4));
605
            // validate received ID
606
            if (lastid < _deserialize(canRxFrame.data8, 4)) {
607
              // store received ID
608
              lastid = _deserialize(canRxFrame.data8, 4);
609
              // restart timeout timer
610
              chVTSet(&timerTimeout, chTimeUS2I(AOS_SYSTEM_SSSP_TIMEOUT), _ssspTimerCallback, &eventSourceTimeout);
611
              // proceed
612
              stage = STAGE_3_3_WAITFORIDORSIG;
613
            } else {
614
              aosDbgPrintf("ERR: invalid ID\n");
615
              // abort
616
              stage = STAGE_3_4_ABORT_ACTIVE;
617
              flags.wfe_next = false;
618
            }
619
            // explicitely clear timeout event flag
620
            chEvtWaitAnyTimeout(eventListenerTimeout.events, TIME_IMMEDIATE);
621
            eventmask &= ~(eventListenerTimeout.events);
622
          }
623
        }
624
#endif
625
        break;
626
      } /* end of STAGE_3_3_WAITFORFIRSTID */
627

    
628
      case STAGE_3_3_WAITFORIDORSIG:
629
      {
630
#if (AMIROOS_CFG_SSSP_STACK_START != true)
631
        aos.sssp.stage = AOS_SSSP_STARTUP_3_3;
632

    
633
        // a CAN message was received
634
        if (eventmask & eventListenerCan.events) {
635
          // if an ID message was received
636
          if (canRxFrame.DLC == 4 &&
637
              canRxFrame.RTR == CAN_RTR_DATA &&
638
              canRxFrame.IDE == CAN_IDE_STD &&
639
              canRxFrame.SID == SSSP_STACKINIT_CANMSGID_MODULEID) {
640
            aosDbgPrintf("ID (%u)\n", (uint32_t)_deserialize(canRxFrame.data8, 4));
641
            // validate received ID
642
            if (lastid < _deserialize(canRxFrame.data8, 4)) {
643
              // store received ID
644
              lastid = _deserialize(canRxFrame.data8, 4);
645
              // restart timeout timer
646
              chVTSet(&timerTimeout, chTimeUS2I(AOS_SYSTEM_SSSP_TIMEOUT), _ssspTimerCallback, &eventSourceTimeout);
647
            } else {
648
              aosDbgPrintf("ERR: invalid ID\n");
649
              // abort
650
              stage = STAGE_3_4_ABORT_ACTIVE;
651
              flags.wfe_next = false;
652
            }
653
            // explicitely clear timeout event flag
654
            chEvtWaitAnyTimeout(eventListenerTimeout.events, TIME_IMMEDIATE);
655
            eventmask &= ~(eventListenerTimeout.events);
656
          }
657
        }
658

    
659
        // if an IO event was received (DN signal)
660
        if ((eventmask & _eventListenerIO.events) && (ioflags & MODULE_SSSP_EVENTFLAGS_DN)) {
661
          aosDbgPrintf("DN <-\n");
662
          // reset timeout timer
663
          chVTReset(&timerTimeout);
664
          chEvtWaitAnyTimeout(eventListenerTimeout.events, TIME_IMMEDIATE);
665
          eventmask &= ~(eventListenerTimeout.events);
666
          // increment and broadcast ID
667
          aos.sssp.moduleId = lastid + 1;
668
          aosDbgPrintf("CAN -> ID (%u)\n", aos.sssp.moduleId);
669
          canTxFrame.DLC = 4;
670
          canTxFrame.SID = SSSP_STACKINIT_CANMSGID_MODULEID;
671
          _serialize(canTxFrame.data8, aos.sssp.moduleId, 4);
672
          if (canTransmitTimeout(&MODULE_HAL_CAN, CAN_ANY_MAILBOX, &canTxFrame, TIME_IMMEDIATE) != MSG_OK) {
673
            chEvtBroadcast(&eventSourceTimeout);
674
            break;
675
          }
676
          // set delay timer
677
          chVTSet(&timerDelay, chTimeUS2I(AMIROOS_CFG_SSSP_SIGNALDELAY), _ssspTimerCallback, &eventSourceDelay);
678
        }
679

    
680
        // if a delay event occurred
681
        if (eventmask & eventListenerDelay.events) {
682
#if (AMIROOS_CFG_SSSP_STACK_END != true)
683
          // activate UP
684
          aosDbgPrintf("UP+\n");
685
          apalControlGpioSet(&moduleSsspGpioUp, APAL_GPIO_ON);
686
#endif
687
          // deactivate S
688
          aosDbgPrintf("S-\n");
689
          apalControlGpioSet(&moduleSsspGpioSync, APAL_GPIO_OFF);
690
          // reset the timeout timer
691
          chVTSet(&timerTimeout, chTimeUS2I(AOS_SYSTEM_SSSP_TIMEOUT), _ssspTimerCallback, &eventSourceTimeout);
692
          chEvtWaitAnyTimeout(eventListenerTimeout.events, TIME_IMMEDIATE);
693
          eventmask &= ~(eventListenerTimeout.events);
694
          // proceed
695
          stage = STAGE_3_3_WAITFORID;
696
        }
697
#endif
698

    
699
        break;
700
      } /* end of STAGE_3_3_WAITFORIDORSIG */
701

    
702
      case STAGE_3_3_WAITFORID:
703
      {
704
        aos.sssp.stage = AOS_SSSP_STARTUP_3_3;
705

    
706
#if (AMIROOS_CFG_SSSP_STACK_END != true)
707
        // a CAN message was received
708
        if (eventmask & eventListenerCan.events) {
709
          // if an ID message was received
710
          if (canRxFrame.DLC == 4 &&
711
              canRxFrame.RTR == CAN_RTR_DATA &&
712
              canRxFrame.IDE == CAN_IDE_STD &&
713
              canRxFrame.SID == SSSP_STACKINIT_CANMSGID_MODULEID) {
714
#if (AMIROOS_CFG_SSSP_STACK_START != true) || (AMIROOS_CFG_DBG == true)
715
            // Plausibility of the received ID is not checked at this point but is done by other modules still in a previous stage.
716
            lastid = _deserialize(canRxFrame.data8, 4);
717
            aosDbgPrintf("ID (%u)\n", lastid);
718
#endif
719
            // restart timeout timer
720
            chVTSet(&timerTimeout, chTimeUS2I(AOS_SYSTEM_SSSP_TIMEOUT), _ssspTimerCallback, &eventSourceTimeout);
721
            chEvtWaitAnyTimeout(eventListenerTimeout.events, TIME_IMMEDIATE);
722
            eventmask &= ~(eventListenerTimeout.events);
723
          }
724
        }
725
#endif
726

    
727
        break;
728
      } /* end of STAGE_3_3_WAITFORID */
729

    
730
      case STAGE_3_4_FINISH:
731
      {
732
        aos.sssp.stage = AOS_SSSP_STARTUP_3_4;
733

    
734
        // if an IO event was received (S signal)
735
        if ((eventmask & _eventListenerIO.events) && (ioflags & MODULE_SSSP_EVENTFLAGS_SYNC)) {
736
          // reset the timeout timer
737
          chVTReset(&timerTimeout);
738
          chEvtWaitAnyTimeout(eventListenerTimeout.events, TIME_IMMEDIATE);
739
          eventmask &= ~(eventListenerTimeout.events);
740
          //set the delay timer
741
          chVTSet(&timerDelay, chTimeUS2I(AOS_SYSTEM_SSSP_TIMEOUT), _ssspTimerCallback, &eventSourceDelay);
742
        }
743

    
744
        // if a CAN event was received
745
        if (eventmask & eventListenerCan.events) {
746
          // if an abort message was received
747
          if (canRxFrame.SID == SSSP_STACKINIT_CANMSGID_ABORT) {
748
            aosDbgPrintf("abort msg\n");
749
            // reset the delay timer
750
            chVTReset(&timerDelay);
751
            chEvtWaitAnyTimeout(eventListenerDelay.events, TIME_IMMEDIATE);
752
            eventmask &= ~(eventListenerDelay.events);
753
            // proceed
754
            stage = STAGE_3_4_ABORT;
755
          }
756
        }
757

    
758
        // if a delay timer event occurred
759
        if (eventmask & eventListenerDelay.events) {
760
          aosDbgPrintf("sequence sucessful\n");
761
          // sequence finished sucessfully
762
          flags.loop = false;
763
        }
764

    
765
        break;
766
      } /* end of STAGE_3_4_FINISH */
767

    
768
      case STAGE_3_4_ABORT_ACTIVE:
769
      {
770
        aos.sssp.stage = AOS_SSSP_STARTUP_3_4;
771

    
772
        // emit abort message
773
        canTxFrame.DLC = 0;
774
        canTxFrame.SID = SSSP_STACKINIT_CANMSGID_ABORT;
775
        canTransmitTimeout(&MODULE_HAL_CAN, CAN_ANY_MAILBOX, &canTxFrame, TIME_INFINITE);
776
        aosDbgPrintf("CAN -> abort\n");
777
        // clear timeout flag
778
        eventmask &= ~(eventListenerTimeout.events);
779
        // proceed immediately
780
        stage = STAGE_3_4_ABORT;
781
        flags.wfe_next = false;
782
        break;
783
      } /* end of STAGE_3_4_ABORT_ACTIVE */
784

    
785
      case STAGE_3_4_ABORT:
786
      {
787
        aos.sssp.stage = AOS_SSSP_STARTUP_3_4;
788

    
789
        // deactivate S
790
        aosDbgPrintf("S-\n");
791
        apalControlGpioSet(&moduleSsspGpioSync, APAL_GPIO_OFF);
792
        // invalidate module ID
793
        aos.sssp.moduleId = 0;
794

    
795
        // if an IO event was received (S signal)
796
        if ((eventmask & _eventListenerIO.events) && (ioflags & MODULE_SSSP_EVENTFLAGS_SYNC)) {
797
          aosDbgPrintf("sequence aborted\n");
798
          // exit the sequence
799
          flags.loop = false;
800
        }
801

    
802
        break;
803
      } /* end of STAGE_3_4_ABORT */
804
    }
805

    
806
    // fetch pending CAN message (if any)
807
    if ((eventmask & eventListenerCan.events) && (canReceiveTimeout(&MODULE_HAL_CAN, CAN_ANY_MAILBOX, &canRxFrame, TIME_IMMEDIATE) == MSG_OK)) {
808
      aosDbgPrintf("CAN <- 0x%03X\n", canRxFrame.SID);
809
      flags.wfe_next = false;
810
    }
811

    
812
    // handle unhandled timeout events
813
    if (eventmask & eventListenerTimeout.events) {
814
      aosDbgPrintf("ERR: timeout evt\n");
815
      // abort
816
      flags.wfe_next = false;
817
      stage = STAGE_3_4_ABORT_ACTIVE;
818
    }
819

    
820
    // apply wfe value for next iteration
821
    flags.wfe = flags.wfe_next;
822
  } /* end of FSM loop */
823
  aosDbgPrintf("\n");
824

    
825
  // unregister all events (timeout, delay, CAN receive)
826
  chEvtUnregister(&eventSourceTimeout, &eventListenerTimeout);
827
  chEvtUnregister(&eventSourceDelay, &eventListenerDelay);
828
  chEvtUnregister(&MODULE_HAL_CAN.rxfull_event, &eventListenerCan);
829
  // clear any pending events (timeout, delay, CAN receive)
830
  chEvtWaitAllTimeout(TIMEOUTEVENT_MASK | DELAYEVENT_MASK | CANEVENT_MASK, TIME_IMMEDIATE);
831

    
832
  // reset all control signals
833
#if (AMIROOS_CFG_SSSP_STACK_END != true)
834
  apalControlGpioSet(&moduleSsspGpioUp, APAL_GPIO_OFF);
835
#endif
836
  apalControlGpioSet(&moduleSsspGpioSync, APAL_GPIO_OFF);
837

    
838
  return shutdown;
839
}
840

    
841
/**
842
 * @brief   Application entry point.
843
 */
844
int main(void)
845
{
846
  // local variables
847
  eventmask_t eventmask = 0;
848
  eventflags_t eventflags = 0;
849
  aos_shutdown_t shutdown = AOS_SHUTDOWN_NONE;
850
#if defined(AMIROOS_CFG_MAIN_EXTRA_THREAD_VARIABLES)
851
  AMIROOS_CFG_MAIN_EXTRA_THREAD_VARIABLES
852
#endif
853

    
854
  /*
855
   * ##########################################################################
856
   * # system initialization                                                  #
857
   * ##########################################################################
858
   */
859

    
860
#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_0)
861
#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_0_ARGS)
862
  AMIROOS_CFG_MAIN_INIT_HOOK_0(AMIROOS_CFG_MAIN_INIT_HOOK_0_ARGS);
863
#else
864
  AMIROOS_CFG_MAIN_INIT_HOOK_0();
865
#endif
866
#endif
867

    
868
  /* hardware, kernel, and operating system initialization */
869
  // ChibiOS/HAL and custom hal additions (if any)
870
  halInit();
871
#ifdef MODULE_INIT_HAL_EXTRA
872
  MODULE_INIT_HAL_EXTRA();
873
#endif
874

    
875
#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_1)
876
#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_1_ARGS)
877
  AMIROOS_CFG_MAIN_INIT_HOOK_1(AMIROOS_CFG_MAIN_INIT_HOOK_1_ARGS);
878
#else
879
  AMIROOS_CFG_MAIN_INIT_HOOK_1();
880
#endif
881
#endif
882

    
883
  // ChibiOS/RT kernel and custom kernel additions (if any)
884
  chSysInit();
885
#ifdef MODULE_INIT_KERNEL_EXTRA
886
  MODULE_INIT_KERNEL_EXTRA();
887
#endif
888

    
889
#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_2)
890
#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_2_ARGS)
891
  AMIROOS_CFG_MAIN_INIT_HOOK_2(AMIROOS_CFG_MAIN_INIT_HOOK_2_ARGS);
892
#else
893
  AMIROOS_CFG_MAIN_INIT_HOOK_2();
894
#endif
895
#endif
896

    
897
  // AMiRo-OS and custom OS additions (if any)
898
#if (AMIROOS_CFG_SHELL_ENABLE == true)
899
  aosSysInit(moduleShellPrompt);
900
#else
901
  aosSysInit();
902
#endif
903
#ifdef MODULE_INIT_OS_EXTRA
904
  MODULE_INIT_OS_EXTRA();
905
#endif
906

    
907
#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_3)
908
#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_3_ARGS)
909
  AMIROOS_CFG_MAIN_INIT_HOOK_3(AMIROOS_CFG_MAIN_INIT_HOOK_3_ARGS);
910
#else
911
  AMIROOS_CFG_MAIN_INIT_HOOK_3();
912
#endif
913
#endif
914

    
915
#if (AMIROOS_CFG_TESTS_ENABLE == true)
916
#if defined(MODULE_INIT_TESTS)
917
  MODULE_INIT_TESTS();
918
#else
919
  #warning "MODULE_INIT_TESTS not defined"
920
#endif
921
#endif
922

    
923
#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_4)
924
#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_4_ARGS)
925
  AMIROOS_CFG_MAIN_INIT_HOOK_4(AMIROOS_CFG_MAIN_INIT_HOOK_4_ARGS);
926
#else
927
  AMIROOS_CFG_MAIN_INIT_HOOK_4();
928
#endif
929
#endif
930

    
931
  /* event associations */
932
#if (AMIROOS_CFG_SSSP_STACK_START == true) && (AMIROOS_CFG_SSSP_STACK_END == true)
933
  chEvtRegisterMaskWithFlags(&aos.events.io, &_eventListenerIO, IOEVENT_MASK, MODULE_SSSP_EVENTFLAGS_PD | MODULE_SSSP_EVENTFLAGS_SYNC);
934
#elif (AMIROOS_CFG_SSSP_STACK_START == true)
935
  chEvtRegisterMaskWithFlags(&aos.events.io, &_eventListenerIO, IOEVENT_MASK, MODULE_SSSP_EVENTFLAGS_PD | MODULE_SSSP_EVENTFLAGS_SYNC | MODULE_SSSP_EVENTFLAGS_UP);
936
#elif (AMIROOS_CFG_SSSP_STACK_END == true)
937
  chEvtRegisterMaskWithFlags(&aos.events.io, &_eventListenerIO, IOEVENT_MASK, MODULE_SSSP_EVENTFLAGS_PD | MODULE_SSSP_EVENTFLAGS_SYNC | MODULE_SSSP_EVENTFLAGS_DN);
938
#else
939
  chEvtRegisterMaskWithFlags(&aos.events.io, &_eventListenerIO, IOEVENT_MASK, MODULE_SSSP_EVENTFLAGS_PD | MODULE_SSSP_EVENTFLAGS_SYNC | MODULE_SSSP_EVENTFLAGS_DN | MODULE_SSSP_EVENTFLAGS_UP);
940
#endif
941
  chEvtRegisterMask(&aos.events.os, &_eventListenerOS, OSEVENT_MASK);
942

    
943
#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_5)
944
#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_5_ARGS)
945
  AMIROOS_CFG_MAIN_INIT_HOOK_5(AMIROOS_CFG_MAIN_INIT_HOOK_5_ARGS);
946
#else
947
  AMIROOS_CFG_MAIN_INIT_HOOK_5();
948
#endif
949
#endif
950

    
951
  /* periphery communication initialization */
952
  // CAN (mandatory)
953
  canStart(&MODULE_HAL_CAN, &moduleHalCanConfig);
954
  // module specific initialization (if any)
955
#ifdef MODULE_INIT_PERIPHERY_COMM
956
  MODULE_INIT_PERIPHERY_COMM();
957
#endif
958
  // user interface (if any)
959
#ifdef MODULE_HAL_PROGIF
960
  aosIOChannelInit(&_stdiochannel, (BaseAsynchronousChannel*)&MODULE_HAL_PROGIF);
961
  aosIOChannelOutputEnable(&_stdiochannel);
962
  aosIOStreamAddChannel(&aos.iostream, &_stdiochannel);
963
#if (AMIROOS_CFG_SHELL_ENABLE == true)
964
  aosShellChannelInit(&_stdshellchannel, (BaseAsynchronousChannel*)&MODULE_HAL_PROGIF);
965
  aosShellChannelInputEnable(&_stdshellchannel);
966
  aosShellChannelOutputEnable(&_stdshellchannel);
967
  aosShellStreamAddChannel(&aos.shell.stream, &_stdshellchannel);
968
#endif
969
#endif
970

    
971
#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_6)
972
#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_6_ARGS)
973
  AMIROOS_CFG_MAIN_INIT_HOOK_6(AMIROOS_CFG_MAIN_INIT_HOOK_6_ARGS);
974
#else
975
  AMIROOS_CFG_MAIN_INIT_HOOK_6();
976
#endif
977
#endif
978

    
979
  /* module is ready -> print welcome prompt */
980
  aosprintf("\n");
981
  aosprintf("######################################################################\n");
982
  aosprintf("# AMiRo-OS is an operating system designed for the Autonomous Mini   #\n");
983
  aosprintf("# Robot (AMiRo) platform.                                            #\n");
984
  aosprintf("# Copyright (C) 2016..2018  Thomas Schöpping et al.                  #\n");
985
  aosprintf("#                                                                    #\n");
986
  aosprintf("# This is free software; see the source for copying conditions.      #\n");
987
  aosprintf("# There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR  #\n");
988
  aosprintf("# A PARTICULAR PURPOSE.                                              #\n");
989
  aosprintf("# The development of this software was supported by the Excellence   #\n");
990
  aosprintf("# Cluster EXC 227 Cognitive Interaction Technology. The Excellence   #\n");
991
  aosprintf("# Cluster EXC 227 is a grant of the Deutsche Forschungsgemeinschaft  #\n");
992
  aosprintf("# (DFG) in the context of the German Excellence Initiative.          #\n");
993
  aosprintf("######################################################################\n");
994
  aosprintf("\n");
995

    
996
#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_7)
997
#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_7_ARGS)
998
  AMIROOS_CFG_MAIN_INIT_HOOK_7(AMIROOS_CFG_MAIN_INIT_HOOK_7_ARGS);
999
#else
1000
  AMIROOS_CFG_MAIN_INIT_HOOK_7();
1001
#endif
1002
#endif
1003

    
1004
  /* SSSP startup OS synchronization phase (end of startup stage 2) */
1005
  while ((shutdown == AOS_SHUTDOWN_NONE) && (eventmask = aosSysSsspStartupOsInitSyncCheck(&_eventListenerIO)) != 0) {
1006
    /*
1007
     * This code is executed if the received event was not about the SYS_SYNC control signal.
1008
     * The returned event could be caused by any listener (not only the argument).
1009
     */
1010
    // IO event
1011
    if (eventmask & _eventListenerIO.events) {
1012
      eventflags = chEvtGetAndClearFlags(&_eventListenerIO);
1013
      // PD event
1014
      if (eventflags & MODULE_SSSP_EVENTFLAGS_PD) {
1015
        shutdown = AOS_SHUTDOWN_PASSIVE;
1016
      } else {
1017
#ifdef MODULE_SSSP_STARTUP_2_2_IOEVENT_HOOK
1018
        MODULE_SSSP_STARTUP_2_2_IOEVENT_HOOK(eventmask, eventflags);
1019
#else
1020
        // ignore any other IO events
1021
#endif
1022
      }
1023
    }
1024
    // OS event
1025
    else if (eventmask & _eventListenerOS.events) {
1026
      eventflags = chEvtGetAndClearFlags(&_eventListenerOS);
1027
      _unexpectedEventError(eventmask, eventflags);
1028
    }
1029
    // unknown event
1030
    else {
1031
      _unexpectedEventError(eventmask, 0);
1032
    }
1033
  }
1034

    
1035
  /*
1036
   * There must be no delays at this point, thus no hook is allowed.
1037
   */
1038

    
1039
  /* SSSP startup stage 3 (module stack initialization) */
1040
  if (shutdown == AOS_SHUTDOWN_NONE) {
1041
    shutdown = _ssspModuleStackInitialization();
1042
  }
1043

    
1044
  /*
1045
   * There must be no delays at this point, thus no hook is allowed.
1046
   */
1047

    
1048
  /* snychronize calendars */
1049
  if (shutdown == AOS_SHUTDOWN_NONE) {
1050
#if (AMIROOS_CFG_SSSP_MASTER == true)
1051
    CANTxFrame frame;
1052
    struct tm t;
1053
    uint64_t encoded;
1054

    
1055
    frame.DLC = 8;
1056
    frame.RTR = CAN_RTR_DATA;
1057
    frame.IDE = CAN_IDE_STD;
1058
    frame.SID = CALENDERSYNC_CANMSGID;
1059

    
1060
    aosDbgPrintf("transmitting current date/time...\t");
1061
    // get current date & time
1062
    aosSysGetDateTime(&t);
1063
    // encode
1064
    encoded = _TM2U64(&t);
1065
    // serialize
1066
    _serialize(frame.data8, encoded, 8);
1067
    // transmit
1068
    canTransmitTimeout(&MODULE_HAL_CAN, CAN_ANY_MAILBOX, &frame, TIME_IMMEDIATE);
1069

    
1070
    aosDbgPrintf("done\n");
1071
#else
1072
    CANRxFrame frame;
1073
    uint64_t encoded;
1074
    struct tm t;
1075

    
1076
    aosDbgPrintf("receiving current date/time...\t");
1077
    // receive message
1078
    if (canReceiveTimeout(&MODULE_HAL_CAN, CAN_ANY_MAILBOX, &frame, chTimeUS2I(AOS_SYSTEM_SSSP_TIMEOUT)) == MSG_OK) {
1079
      // validate message
1080
      if (frame.DLC == 8 &&
1081
          frame.RTR == CAN_RTR_DATA &&
1082
          frame.IDE == CAN_IDE_STD &&
1083
          frame.SID == CALENDERSYNC_CANMSGID) {
1084
        // deserialize
1085
        encoded = _deserialize(frame.data8, 8);
1086
        // decode
1087
        _U642TM(&t, encoded);
1088
        // set current date & time
1089
        aosSysSetDateTime(&t);
1090
        aosDbgPrintf("success\n");
1091
      } else {
1092
        aosDbgPrintf("fail (invalid message)\n");
1093
      }
1094
    } else {
1095
      aosDbgPrintf("fail (timeout)\n");
1096
    }
1097
#endif
1098
    aosDbgPrintf("\n");
1099
  }
1100

    
1101
#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_8)
1102
#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_8_ARGS)
1103
  AMIROOS_CFG_MAIN_INIT_HOOK_8(AMIROOS_CFG_MAIN_INIT_HOOK_8_ARGS);
1104
#else
1105
  AMIROOS_CFG_MAIN_INIT_HOOK_8();
1106
#endif
1107
#endif
1108

    
1109
  /* completely start AMiRo-OS */
1110
  if (shutdown == AOS_SHUTDOWN_NONE) {
1111
    aosSysStart();
1112
  }
1113

    
1114
#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_9)
1115
#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_9_ARGS)
1116
  AMIROOS_CFG_MAIN_INIT_HOOK_9(AMIROOS_CFG_MAIN_INIT_HOOK_9_ARGS);
1117
#else
1118
  AMIROOS_CFG_MAIN_INIT_HOOK_9();
1119
#endif
1120
#endif
1121

    
1122
  /*
1123
   * ##########################################################################
1124
   * # infinite loop                                                          #
1125
   * ##########################################################################
1126
   */
1127

    
1128
  // sleep until a shutdown event is received
1129
  while (shutdown == AOS_SHUTDOWN_NONE) {
1130
    // wait for an event
1131
#if (AMIROOS_CFG_MAIN_LOOP_TIMEOUT != 0)
1132
    eventmask = chEvtWaitOneTimeout(ALL_EVENTS, chTimeUS2I(AMIROOS_CFG_MAIN_LOOP_TIMEOUT));
1133
#else
1134
    eventmask = chEvtWaitOne(ALL_EVENTS);
1135
#endif
1136

    
1137
#if defined(AMIROOS_CFG_MAIN_LOOP_HOOK_0)
1138
#if defined(AMIROOS_CFG_MAIN_LOOP_HOOK_0_ARGS)
1139
    AMIROOS_CFG_MAIN_LOOP_HOOK_0(AMIROOS_CFG_MAIN_LOOP_HOOK_0_ARGS);
1140
#else
1141
    AMIROOS_CFG_MAIN_LOOP_HOOK_0();
1142
#endif
1143
#endif
1144

    
1145
    switch (eventmask) {
1146
      // if this was an I/O event
1147
      case IOEVENT_MASK:
1148
        // evaluate flags
1149
        eventflags = chEvtGetAndClearFlags(&_eventListenerIO);
1150
        // PD event
1151
        if (eventflags & MODULE_SSSP_EVENTFLAGS_PD) {
1152
          shutdown = AOS_SHUTDOWN_PASSIVE;
1153
        }
1154
        // all other events
1155
#ifdef MODULE_MAIN_LOOP_IO_EVENT
1156
        else {
1157
          MODULE_MAIN_LOOP_IO_EVENT(eventmask, eventflags);
1158
        }
1159
#endif
1160
        break;
1161

    
1162
      // if this was an OS event
1163
      case OSEVENT_MASK:
1164
        // evaluate flags
1165
        eventflags = chEvtGetAndClearFlags(&_eventListenerOS);
1166
        switch (eventflags) {
1167
          case AOS_SYSTEM_EVENTFLAGS_HIBERNATE:
1168
            shutdown = AOS_SHUTDOWN_HIBERNATE;
1169
            break;
1170
          case AOS_SYSTEM_EVENTFLAGS_DEEPSLEEP:
1171
            shutdown = AOS_SHUTDOWN_DEEPSLEEP;
1172
            break;
1173
          case AOS_SYSTEM_EVENTFLAGS_TRANSPORTATION:
1174
            shutdown = AOS_SHUTDOWN_TRANSPORTATION;
1175
            break;
1176
          case AOS_SYSTEM_EVENTFLAGS_RESTART:
1177
            shutdown = AOS_SHUTDOWN_RESTART;
1178
            break;
1179
          default:
1180
            _unexpectedEventError(eventmask, eventflags);
1181
            break;
1182
        }
1183
        break;
1184

    
1185
      // if this was any other event (should be impossible to occur)
1186
      default:
1187
        eventflags = 0;
1188
        _unexpectedEventError(eventmask, eventflags);
1189
        break;
1190
    }
1191

    
1192
#if defined(AMIROOS_CFG_MAIN_LOOP_HOOK_1)
1193
#if defined(AMIROOS_CFG_MAIN_LOOP_HOOK_1_ARGS)
1194
    AMIROOS_CFG_MAIN_LOOP_HOOK_1(AMIROOS_CFG_MAIN_LOOP_HOOK_1_ARGS);
1195
#else
1196
    AMIROOS_CFG_MAIN_LOOP_HOOK_1();
1197
#endif
1198
#endif
1199
  }
1200

    
1201
  /*
1202
   * ##########################################################################
1203
   * # system shutdown                                                        #
1204
   * ##########################################################################
1205
   */
1206

    
1207
#if defined(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_0)
1208
#if defined(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_0_ARGS)
1209
    AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_0(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_0_ARGS);
1210
#else
1211
    AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_0();
1212
#endif
1213
#endif
1214

    
1215
  // initialize/acknowledge shutdown
1216
  aosSysShutdownInit(shutdown);
1217

    
1218
#if defined(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_1)
1219
#if defined(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_1_ARGS)
1220
    AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_1(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_1_ARGS);
1221
#else
1222
    AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_1();
1223
#endif
1224
#endif
1225

    
1226
  // stop system threads
1227
  aosSysStop();
1228

    
1229
#if defined(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_2)
1230
#if defined(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_2_ARGS)
1231
    AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_2(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_2_ARGS);
1232
#else
1233
    AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_2();
1234
#endif
1235
#endif
1236

    
1237
  // deinitialize system
1238
  aosSysDeinit();
1239

    
1240
#if defined(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_3)
1241
#if defined(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_3_ARGS)
1242
    AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_3(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_3_ARGS);
1243
#else
1244
    AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_3();
1245
#endif
1246
#endif
1247

    
1248
  /* stop all periphery communication */
1249
  // CAN (mandatory)
1250
  canStop(&MODULE_HAL_CAN);
1251
#ifdef MODULE_SHUTDOWN_PERIPHERY_COMM
1252
  MODULE_SHUTDOWN_PERIPHERY_COMM();
1253
#endif
1254

    
1255
#if defined(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_4)
1256
#if defined(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_4_ARGS)
1257
    AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_4(AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_4_ARGS);
1258
#else
1259
    AMIROOS_CFG_MAIN_SHUTDOWN_HOOK_4();
1260
#endif
1261
#endif
1262

    
1263
  // finally hand over to bootloader
1264
  aosSysShutdownFinal(shutdown);
1265

    
1266
  /*
1267
   * ##########################################################################
1268
   * # after shutdown/restart                                                 #
1269
   * ##########################################################################
1270
   *
1271
   * NOTE: This code will not be executed, since the bootloader callbacks will stop/restart the MCU.
1272
   *       It is included nevertheless for the sake of completeness and to explicitely indicate,
1273
   *       which subsystems should NOT be shut down.
1274
   */
1275

    
1276
  // return an error, since this code should not be executed
1277
  return -1;
1278
}
1279

    
1280
/** @} */