Statistics
| Branch: | Tag: | Revision:

amiro-os / core / src / aos_sssp.c @ 98949060

History | View | Annotate | Download (47.612 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_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
#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
/******************************************************************************/
45
/* EXPORTED VARIABLES                                                         */
46
/******************************************************************************/
47

    
48
/******************************************************************************/
49
/* LOCAL TYPES                                                                */
50
/******************************************************************************/
51

    
52
/******************************************************************************/
53
/* LOCAL VARIABLES                                                            */
54
/******************************************************************************/
55

    
56
/**
57
 * @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
 * @brief   A timer event based delays.
86
 * @details This timer must not be an AMiRo-OS timer, since delays occurr before system is initialized.
87
 */
88
static virtual_timer_t _delayTimer;
89

    
90
/**
91
 * @brief   Event source for the delay timer.
92
 */
93
static event_source_t _delayEventSource;
94

    
95
/**
96
 * @brief   Event listener for the delay event.
97
 */
98
static event_listener_t _delayEventListener;
99

    
100
/******************************************************************************/
101
/* LOCAL FUNCTIONS                                                            */
102
/******************************************************************************/
103

    
104
#if (AMIROOS_CFG_SSSP_MASTER != true) || defined(__DOXYGEN__)
105

    
106
/**
107
 * @brief   Callback function for the S signal interrupt.
108
 *
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
    apalControlGpioGet(moduleSsspSignalS(), &s);
124
    // 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
 * @details Toggles the S signal and reconfigures the system synchronization timer.
159
 *
160
 * @param[in] par   Unused parameters.
161
 */
162
static void _syncTimerCallback(void* par)
163
{
164
  (void)par;
165

    
166
  // local variables
167
  apalControlGpioState_t state;
168
  aos_timestamp_t uptime;
169

    
170
  chSysLockFromISR();
171
  // toggle and read signal S
172
  apalGpioToggle(moduleSsspSignalS()->gpio);
173
  apalControlGpioGet(moduleSsspSignalS(), &state);
174
  // 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
    chVTSetI(&_synctimer, chTimeUS2I((time_usecs_t)(_synctime - uptime)), _syncTimerCallback, NULL);
180
  }
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
  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

    
206
  return;
207
}
208

    
209
#endif /* (AMIROOS_CFG_SSSP_MASTER == true) */
210

    
211
/**
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
static inline aos_status_t _waitForS(event_listener_t* listener, apalControlGpioState_t signalstate, eventmask_t* received)
237
{
238
  aosDbgCheck(listener != NULL);
239
  aosDbgCheck(received != NULL);
240

    
241
  // local variables
242
  aos_status_t status = AOS_FAILURE;
243

    
244
  // 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
  if (*received & listener->events) {
248
    apalControlGpioState_t s;
249
    apalControlGpioGet(moduleSsspSignalS(), &s);
250
    chSysLock();
251
    // only check for the expected event
252
    if ((listener->flags & moduleSsspEventflagS()) && (s == signalstate)) {
253
      // unset the expected flags but keep any other ones
254
      listener->flags &= ~moduleSsspEventflagS();
255
      status = AOS_SUCCESS;
256
    }
257
    // if no further flags are set
258
    if (listener->flags == 0) {
259
      // clear event
260
      *received &= ~(listener->events);
261
    }
262
    chSysUnlock();
263
  }
264

    
265
  return status;
266
}
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
static inline aos_status_t _delay(uint32_t dt, eventmask_t mask, eventmask_t* received)
278
{
279
  aosDbgCheck(dt != TIME_IMMEDIATE);
280
  aosDbgCheck(mask != 0);
281
  aosDbgCheck(received != NULL);
282

    
283
  // arm the delay timer once
284
  if (!chVTIsArmed(&_delayTimer)) {
285
    chEvtRegisterMask(&_delayEventSource, &_delayEventListener, mask);
286
    chVTSet(&_delayTimer, chTimeUS2I(dt), _timerCallback, &_delayEventSource);
287
  }
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
  if (*received & _delayEventListener.events) {
294
    chEvtUnregister(&_delayEventSource, &_delayEventListener);
295
    *received &= ~(_delayEventListener.events);
296
    return AOS_SUCCESS;
297
  }
298

    
299
  return AOS_FAILURE;
300
}
301

    
302
#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
aos_status_t _serializeBcbMessage(uint8_t* buffer, aos_ssspbcbmessage_t message)
312
{
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
        buffer[byte+1] = (message.payload.id >> ((sizeof(aos_ssspmoduleid_t) - (byte+1)) * 8)) & 0xFF;
328
      }
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
aos_status_t _deserializeBcbMessage(aos_ssspbcbmessage_t* message, uint8_t* buffer)
346
{
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
        message->payload.id |= (aos_ssspmoduleid_t)(buffer[byte+1] << ((sizeof(aos_ssspmoduleid_t) - (byte+1)) * 8));
365
      }
366
      return AOS_SUCCESS;
367
    }
368
    default:
369
    {
370
      message->type = AOS_SSSP_BCBMESSAGE_INVALID;
371
      return AOS_FAILURE;
372 <