Statistics
| Branch: | Tag: | Revision:

amiro-os / core / src / aos_main.cpp @ e2d7143f

History | View | Annotate | Download (45.046 KB)

1
/*
2
AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
3
Copyright (C) 2016..2019  Thomas Schöpping et al.
4

5
This program is free software: you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation, either version 3 of the License, or
8
(at your option) any later version.
9

10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
GNU General Public License for more details.
14

15
You should have received a copy of the GNU General Public License
16
along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
*/
18

    
19
/**
20
 * @file    aos_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 <aos_system.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
#if (AMIROOS_CFG_SSSP_ENABLE == true) || defined(__DOXYGEN__)
65

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

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

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

    
81
#else /* AMIROOS_CFG_SSSP_ENABLE == false */
82

    
83
/**
84
 * @brief   Default shutdown mode if SSSP is unavailable.
85
 */
86
#define AOS_SHUTDOWN_DEFAULT                    AOS_SHUTDOWN_DEEPSLEEP
87

    
88
#endif /* AMIROOS_CFG_SSSP_ENABLE */
89

    
90
/**
91
 * @brief   CAN message identifier for calender synchronization message.
92
 */
93
#define CALENDERSYNC_CANMSGID                   0x004
94

    
95
/**
96
 * @brief   Listener object for I/O events.
97
 */
98
static event_listener_t _eventListenerIO;
99

    
100
/**
101
 * @brief   Listener object for OS events.
102
 */
103
static event_listener_t _eventListenerOS;
104

    
105
#if defined(MODULE_HAL_PROGIF) || defined(__DOXYGEN__)
106
/**
107
 * @brief   I/O channel for the programmer interface.
108
 */
109
static AosIOChannel _stdiochannel;
110

    
111
#if (AMIROOS_CFG_SHELL_ENABLE == true) || (AMIROOS_CFG_TESTS_ENABLE == true) || defined(__DOXYGEN__)
112
/**
113
 * @brief   I/O shell channel for the programmer interface.
114
 */
115
static AosShellChannel _stdshellchannel;
116
#endif /* (AMIROOS_CFG_SHELL_ENABLE == true) || (AMIROOS_CFG_TESTS_ENABLE == true)*/
117
#endif /* defined(MODULE_HAL_PROGIF) */
118

    
119
/*
120
 * hook to add further static variables
121
 */
122
#if defined(AMIROOS_CFG_MAIN_EXTRA_STATIC_VARIABLES)
123
AMIROOS_CFG_MAIN_EXTRA_STATIC_VARIABLES
124
#endif
125

    
126
/**
127
 * @brief   Prints an error message about an unexpected event.
128
 *
129
 * @param[in] mask    The event mask.
130
 * @param[in] flags   The event flags.
131
 */
132
static inline void _unexpectedEventError(const eventmask_t mask, const eventflags_t flags)
133
{
134
#if (AMIROOS_CFG_DBG == true)
135
  aosprintf("CTRL: unexpected/unknown event received. mask: 0x%08X; flags: 0x%08X\n", mask, flags);
136
#else
137
  (void)(mask);
138
  (void)(flags);
139
#endif
140
  return;
141
}
142

    
143
#if (AMIROOS_CFG_SSSP_ENABLE == true) || defined(__DOXYGEN__)
144
/**
145
 * @brief   Callback function to be used during SSSP stack initialization sequence.
146
 *
147
 * @param[in] par   A pointer to an @p event_source_t to be fired.
148
 */
149
static void _ssspTimerCallback(void* par)
150
{
151
  aosDbgCheck(par != NULL);
152

    
153
  chSysLockFromISR();
154
  chEvtBroadcastI((event_source_t*)par);
155
  chSysUnlockFromISR();
156

    
157
  return;
158
}
159
#endif /* AMIROOS_CFG_SSSP_ENABLE == true */
160

    
161
/**
162
 * @brief   Helper function to serialize data.
163
 *
164
 * @param[out]  dst   Pointer to the output buffer.
165
 * @param[in]   src   Data to be serialized.
166
 * @param[in]   n     Number of bytes to serialize.
167
 */
168
inline void _serialize(uint8_t* dst, const uint64_t src, const uint8_t n)
169
{
170
  aosDbgCheck(dst != NULL);
171
  aosDbgCheck(n > 0 && n <= 8);
172

    
173
  for (uint8_t byte = 0; byte < n; ++byte) {
174
    dst[byte] = (uint8_t)((src >> (byte * 8)) & 0xFF);
175
  }
176

    
177
  return;
178
}
179

    
180
/**
181
 * @brief   Helper function to deserialize data.
182
 *
183
 * @param[in] src   Pointer to the buffer of data to be deserialzed.
184
 * @param[in] n     Number of bytes to deserialize.
185
 *
186
 * @return    The deserialized 32 bit data.
187
 */
188
inline uint64_t _deserialize(uint8_t* src, const uint8_t n)
189
{
190
  aosDbgCheck(src != NULL);
191
  aosDbgCheck(n > 0 && n <= 8);
192

    
193
  uint64_t result = 0;
194
  for (uint8_t byte = 0; byte < n; ++byte) {
195
    result |= ((uint64_t)src[byte]) << (byte * 8);
196
  }
197

    
198
  return result;
199
}
200

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

    
222
  return (((uint64_t)(src->tm_sec  & 0x0000003F) << (0))               |
223
          ((uint64_t)(src->tm_min  & 0x0000003F) << (6))               |
224
          ((uint64_t)(src->tm_hour & 0x0000001F) << (12))              |
225
          ((uint64_t)(src->tm_mday & 0x0000001F) << (17))              |
226
          ((uint64_t)(src->tm_mon  & 0x0000000F) << (22))              |
227
          ((uint64_t)(src->tm_year & 0x00FFFFFF) << (26))              |
228
          ((uint64_t)(src->tm_wday & 0x00000007) << (50))              |
229
          ((uint64_t)(src->tm_yday & 0x000001FF) << (53))              |
230
          ((uint64_t)((src->tm_isdst == 0) ? 0 : (src->tm_isdst > 0) ? 1 : 2) << (62)));
231
}
232

    
233
/**
234
 * @brief   Converter functiomn to retrieve the encoded TM value from an unsigned 64 bit integer.
235
 *
236
 * @details For information on the encoding, please refer to @p _TM2U64 function.
237
 *
238
 * @param[out] dst  The TM struct to fill with the decoded values.
239
 * @param[in]  src  Unsigned 64 bit integer holding the encoded TM value.
240
 */
241
inline void _U642TM(struct tm* dst, const uint64_t src)
242
{
243
  aosDbgCheck(dst != NULL);
244

    
245
  dst->tm_sec  = (src >> 0)  & 0x0000003F;
246
  dst->tm_min  = (src >> 6)  & 0x0000003F;
247
  dst->tm_hour = (src >> 12) & 0x0000001F;
248
  dst->tm_mday = (src >> 17) & 0x0000001F;
249
  dst->tm_mon  = (src >> 22) & 0x0000000F;
250
  dst->tm_year = (src >> 26) & 0x00FFFFFF;
251
  dst->tm_wday = (src >> 50) & 0x00000007;
252
  dst->tm_yday = (src >> 53) & 0x000001FF;
253
  dst->tm_isdst = (((src >> 62) & 0x03) == 0) ? 0 : (((src >> 62) & 0x03) > 0) ? 1 : -1;
254

    
255
  return;
256
}
257

    
258
#if (AMIROOS_CFG_SSSP_ENABLE == true) || defined(__DOXYGEN__)
259
/**
260
 * @brief   Implementation of the SSSP module stack initialization sequence (startup phase 3).
261
 *
262
 * @return Shutdown value.
263
 * @retval AOS_SHUTDOWN_NONE      No shutdown signal received
264
 * @retval AOS_SHUTDOWN_PASSIVE   Shutdown signal received.
265
 */
266
aos_shutdown_t _ssspModuleStackInitialization(void)
267
{
268
  // local types
269
  /**
270
   * @brief   States for the internal state machine to implement SSSP startup stage 3.
271
   */
272
  typedef enum {
273
    STAGE_3_1,                  /**< Initiation of SSSP startup stage 3. */
274
    STAGE_3_2,                  /**< Starting the sequence and broadcasting the first ID. */
275
    STAGE_3_3_WAITFORFIRSTID,   /**< Waiting for first ID after initiation. */
276
    STAGE_3_3_WAITFORIDORSIG,   /**< Waiting for next ID or activation of neighbor signal. */
277
    STAGE_3_3_WAITFORID,        /**< Waiting for next ID (after the module has set its own ID). */
278
    STAGE_3_4_FINISH,           /**< Successful finish of stage 3. */
279
    STAGE_3_4_ABORT_ACTIVE,     /**< Aborting stage 3 (active). */
280
    STAGE_3_4_ABORT,            /**< Aborting stage 3 (passive). */
281
  } sssp_modulestackinitstage_t;
282

    
283
  typedef struct {
284
    bool loop     : 1;
285
    bool wfe      : 1;
286
    bool wfe_next : 1;
287
  } flags_t;
288

    
289
  // local variables
290
  aos_shutdown_t shutdown = AOS_SHUTDOWN_NONE;
291
  sssp_modulestackinitstage_t stage = STAGE_3_1;
292
  eventmask_t eventmask = 0;
293
  eventflags_t ioflags = 0;
294
  event_source_t eventSourceTimeout;
295
  event_source_t eventSourceDelay;
296
  event_listener_t eventListenerTimeout;
297
  event_listener_t eventListenerDelay;
298
  event_listener_t eventListenerCan;
299
  virtual_timer_t timerTimeout;
300
  virtual_timer_t timerDelay;
301
  CANTxFrame canTxFrame;
302
  CANRxFrame canRxFrame;
303
#if (AMIROOS_CFG_SSSP_STACK_START != true) || (AMIROOS_CFG_DBG == true)
304
  aos_ssspmoduleid_t lastid = 0;
305
#endif
306
  flags_t flags;
307
  aos_timestamp_t uptime;
308

    
309
  // initialize local varibles
310
  chEvtObjectInit(&eventSourceTimeout);
311
  chEvtObjectInit(&eventSourceDelay);
312
  chVTObjectInit(&timerTimeout);
313
  chVTObjectInit(&timerDelay);
314
  canTxFrame.RTR = CAN_RTR_DATA;
315
  canTxFrame.IDE = CAN_IDE_STD;
316
  flags.loop = true;
317
  flags.wfe = false; // do not wait for events in the initial iteration of the FSM loop
318
  flags.wfe_next = true;
319

    
320
  // initialize system variables
321
  aos.sssp.stage = AOS_SSSP_STARTUP_3_1;
322
  aos.sssp.moduleId = 0;
323

    
324
  // listen to events (timout, delay, CAN receive)
325
  chEvtRegisterMask(&eventSourceTimeout, &eventListenerTimeout, TIMEOUTEVENT_MASK);
326
  chEvtRegisterMask(&eventSourceDelay, &eventListenerDelay, DELAYEVENT_MASK);
327
  chEvtRegisterMask(&MODULE_HAL_CAN.rxfull_event, &eventListenerCan, CANEVENT_MASK);
328

    
329
  /*
330
   * FSM in a loop.
331
   *
332
   * This is a fully event-based FSM for the module stack initialization
333
   * sequence, defined by SSSP as startup stage 3. There are five different
334
   * events that can occur at this point:
335
   *  I/O events: The input level of an input pin has changed. Such events must
336
   *              be handled differently depending on the current state. Most
337
   *              of the time, however, such events can be ignored.
338
   *  OS events:  Such events are only available after this stage completed and
339
   *              thus should never occur. However, there is an optional hook
340
   *              to handle such events, nevertheless.
341
   *  CAN events: At least one CAN message was received. Note that this event
342
   *              will only fire again if all input buffers have been cleared.
343
   *  timeouts:   If some module does not support the sequence of there is any
344
   *              issue, such a case is detected via timeouts and must be
345
   *              handled accordingly (see abort state). In some cases, it is
346
   *              possible that a timeout event occurres 'simultaneously' with
347
   *              some other event. This can be caused by several timing issues
348
   *              and is a valid situation. As a result, any other events
349
   *              should be handled before the timeout event. If the other
350
   *              events are expected and valid, this implementation requires
351
   *              the timeout event flag to be cleared explicitely. Otherwise
352
   *              it is evaluated at the end of each iteration of the loop.
353
   *  delays:     Depending on the current state, delays are required by SSSP
354
   *              for timing of the sequential activation of signals.
355
   */
356
  aosDbgPrintf("SSSP stack initialization sequence:\n");