commit c53ef0b19cb670c47c2e3d9390f62e7661659e32
Author: Thomas Schöpping <tschoepp@cit-ec.uni-bielefeld.de>
Date:   Mon Nov 11 16:33:58 2019 +0100

    MSI implemented

diff --git a/core/src/aos_sssp.c b/core/src/aos_sssp.c
index 8f82143..90ceab1 100644
--- a/core/src/aos_sssp.c
+++ b/core/src/aos_sssp.c
@@ -83,18 +83,19 @@ static float _syncskew;
 
 /**
  * @brief   A timer event based delays.
+ * @details This timer must not be an AMiRo-OS timer, since delays occurr before system is initialized.
  */
 static virtual_timer_t _delayTimer;
 
 /**
  * @brief   Event source for the delay timer.
  */
-static event_source_t _eventSourceDelay;
+static event_source_t _delayEventSource;
 
 /**
  * @brief   Event listener for the delay event.
  */
-static event_listener_t _eventListenerDelay;
+static event_listener_t _delayEventListener;
 
 /******************************************************************************/
 /* LOCAL FUNCTIONS                                                            */
@@ -103,7 +104,7 @@ static event_listener_t _eventListenerDelay;
 #if (AMIROOS_CFG_SSSP_MASTER != true) || defined(__DOXYGEN__)
 
 /**
- * @brief   Callback function for the Sync signal interrupt.
+ * @brief   Callback function for the S signal interrupt.
  *
  * @param[in] args   Pointer to the GPIO line identifier.
  */
@@ -119,7 +120,7 @@ static void _gpioCallbackSSignal(void *args)
   // if the system is in operation phase
   if (aos.sssp.stage == AOS_SSSP_STAGE_OPERATION) {
     // read signal S
-    apalControlGpioGet(&moduleSsspGpioS, &s);
+    apalControlGpioGet(moduleSsspSignalS(), &s);
     // if S was toggled from on to off
     if (s == APAL_GPIO_OFF) {
       // get current uptime
@@ -154,7 +155,7 @@ static void _gpioCallbackSSignal(void *args)
 
 /**
  * @brief   Periodic system synchronization callback function.
- * @details Toggles the SYS_SYNC signal and reconfigures the system synchronization timer.
+ * @details Toggles the S signal and reconfigures the system synchronization timer.
  *
  * @param[in] par   Unused parameters.
  */
@@ -162,19 +163,20 @@ static void _syncTimerCallback(void* par)
 {
   (void)par;
 
+  // local variables
   apalControlGpioState_t state;
   aos_timestamp_t uptime;
 
   chSysLockFromISR();
   // toggle and read signal S
-  apalGpioToggle(moduleSsspGpioS.gpio);
-  apalControlGpioGet(&moduleSsspGpioS, &state);
+  apalGpioToggle(moduleSsspSignalS()->gpio);
+  apalControlGpioGet(moduleSsspSignalS(), &state);
   // if S was toggled from off to on
   if (state == APAL_GPIO_ON) {
     // reconfigure the timer precisely, because the logically falling edge (next interrupt) snychronizes the system time
     _synctime += AMIROOS_CFG_SSSP_SYSSYNCPERIOD;
     aosSysGetUptimeX(&uptime);
-    chVTSetI(&_synctimer, chTimeUS2I(_synctime - uptime), _syncTimerCallback, NULL);
+    chVTSetI(&_synctimer, chTimeUS2I((time_usecs_t)(_synctime - uptime)), _syncTimerCallback, NULL);
   }
   // if S was toggled from on to off
   else /* if (state == APAL_GPIO_OFF) */ {
@@ -199,7 +201,7 @@ static inline void _syncTimerStartS(void)
   aos_timestamp_t t;
   aosSysGetUptimeX(&t);
   t = AMIROOS_CFG_SSSP_SYSSYNCPERIOD - (t % AMIROOS_CFG_SSSP_SYSSYNCPERIOD);
-  chVTSetI(&_synctimer, chTimeUS2I((t > (AMIROOS_CFG_SSSP_SYSSYNCPERIOD / 2)) ? (t - (AMIROOS_CFG_SSSP_SYSSYNCPERIOD / 2)) : (t + (AMIROOS_CFG_SSSP_SYSSYNCPERIOD / 2))), _syncTimerCallback, NULL);
+  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);
 
   return;
 }
@@ -226,33 +228,41 @@ static void _timerCallback(void* par)
  * @brief   Waits for the S signal to switch to the desired state.
  *
  * @param[in]   listener      Pointer to the GPIO event listener to be used.
- * @param[in]   flags         Event flags to listen to by the event listener (indicating a S signal event).
  * @param[in]   signalstate   Desired state of the S signal ti be waited for.
  * @param[out]  received      Output variable to store the received event mask to.
  *
  * @return  Status, indicating whether the expected event was received.
  */
-static inline aos_status_t _waitForS(event_listener_t* listener, eventflags_t flags, apalControlGpioState_t signalstate, eventmask_t* received)
+static inline aos_status_t _waitForS(event_listener_t* listener, apalControlGpioState_t signalstate, eventmask_t* received)
 {
   aosDbgCheck(listener != NULL);
-  aosDbgCheck(flags != 0);
   aosDbgCheck(received != NULL);
 
+  // local variables
+  aos_status_t status = AOS_FAILURE;
+
   // wait for the next event (do not apply any filters in order not to miss any events)
   *received = chEvtWaitOne(ALL_EVENTS);
   // if the correct event was triggered
-  if (*received == listener->events) {
+  if (*received & listener->events) {
     apalControlGpioState_t s;
-    apalControlGpioGet(&moduleSsspGpioS, &s);
+    apalControlGpioGet(moduleSsspSignalS(), &s);
+    chSysLock();
     // only check for the expected event
-    if (flags & listener->flags && s == signalstate) {
+    if ((listener->flags & moduleSsspEventflagS()) && (s == signalstate)) {
       // unset the expected flags but keep any other ones
-      listener->flags &= ~flags;
-      return AOS_SUCCESS;
+      listener->flags &= ~moduleSsspEventflagS();
+      status = AOS_SUCCESS;
     }
+    // if no further flags are set
+    if (listener->flags == 0) {
+      // clear event
+      *received &= ~(listener->events);
+    }
+    chSysUnlock();
   }
 
-  return AOS_FAILURE;
+  return status;
 }
 
 /**
@@ -260,35 +270,159 @@ static inline aos_status_t _waitForS(event_listener_t* listener, eventflags_t fl
  *
  * @param[in]   dt          Delay time in microseconds to be set to the timer.
  * @param[in]   mask        Event mask to be used for the delay timer.
- * @param[in]   arm_timer   Flag to indicate whether the timer has to be armed yet (i.e. on first call of this function).
  * @param[out]  received    Output variable to store the received event mask to.
  *
  * @return  Status, indicating whether the expected event (delay timer) was received.
  */
-static inline aos_status_t _delay(uint32_t dt, eventmask_t mask, bool arm_timer, eventmask_t* received)
+static inline aos_status_t _delay(uint32_t dt, eventmask_t mask, eventmask_t* received)
 {
   aosDbgCheck(dt != TIME_IMMEDIATE);
   aosDbgCheck(mask != 0);
   aosDbgCheck(received != NULL);
 
   // arm the delay timer once
-  if (arm_timer) {
-    chEvtRegisterMask(&_eventSourceDelay, &_eventListenerDelay, mask);
-    chVTSet(&_delayTimer, chTimeUS2I(dt), _timerCallback, &_eventSourceDelay);
+  if (!chVTIsArmed(&_delayTimer)) {
+    chEvtRegisterMask(&_delayEventSource, &_delayEventListener, mask);
+    chVTSet(&_delayTimer, chTimeUS2I(dt), _timerCallback, &_delayEventSource);
   }
 
   // wait for any event to occur (do not apply any filters in order not to miss any events)
   *received = chEvtWaitOne(ALL_EVENTS);
 
   // if the timer event was received, cleanup
-  if (*received & _eventListenerDelay.events) {
-    chEvtUnregister(&_eventSourceDelay, &_eventListenerDelay);
+  if (*received & _delayEventListener.events) {
+    chEvtUnregister(&_delayEventSource, &_delayEventListener);
+    *received &= ~(_delayEventListener.events);
     return AOS_SUCCESS;
   }
 
   return AOS_FAILURE;
 }
 
+#if (AMIROOS_CFG_SSSP_MSI == true) || defined(__DOXYGEN__)
+
+/**
+ * @brief   Serialize a BCB message.
+ * @details The individual primitives are serialized in big-endian fashion.
+ *
+ * @param[out]  buffer    Buffer to write the serialized message to.
+ * @param[in]   message   The message to be serialized.
+ */
+aos_status_t _serializeBcbMessage(uint8_t* buffer, aos_ssspbcbmessage_t message)
+{
+  aosDbgCheck(buffer != NULL);
+
+  // encode the message depending on its type
+  switch (message.type) {
+    case AOS_SSSP_BCBMESSAGE_MSIINIT:
+    case AOS_SSSP_BCBMESSAGE_MSIABORT:
+    {
+      buffer[0] = message.type;
+      return AOS_SUCCESS;
+    }
+    case AOS_SSSP_BCBMESSAGE_MSIID:
+    {
+      buffer[0] = message.type;
+      for (size_t byte = 0; byte < sizeof(aos_ssspmoduleid_t); ++byte) {
+        buffer[byte+1] = (message.payload.id >> (8 * (sizeof(aos_ssspmoduleid_t) - (byte+1)))) & 0xFF;
+      }
+      return AOS_SUCCESS;
+    }
+    default:
+    {
+      return AOS_FAILURE;
+    }
+  }
+}
+
+/**
+ * @brief   Deserialize a BCB message.
+ * @details The individual primitives must be serialized in big-endian fashion.
+ *
+ * @param[out]  message   Message object to be filled.
+ * @param[in]   buffer    Buffer holding the serialized message.
+ */
+aos_status_t _deserializeBcbMessage(aos_ssspbcbmessage_t* message, uint8_t* buffer)
+{
+  aosDbgCheck(message != NULL);
+  aosDbgCheck(buffer != NULL);
+
+  // only decode the first byte, which contains the message type
+  message->type = buffer[0];
+
+  // decode the message depedning on its type
+  switch (message->type) {
+    case AOS_SSSP_BCBMESSAGE_MSIINIT:
+    case AOS_SSSP_BCBMESSAGE_MSIABORT:
+    {
+      return AOS_SUCCESS;
+    }
+    case AOS_SSSP_BCBMESSAGE_MSIID:
+    {
+      message->payload.id = 0;
+      for (size_t byte = 0; byte < sizeof(aos_ssspmoduleid_t); ++byte) {
+        message->payload.id |= (aos_ssspmoduleid_t)(buffer[byte+1] << (8 * (sizeof(aos_ssspmoduleid_t) - (byte+1))));
+      }
+      return AOS_SUCCESS;
+    }
+    default:
+    {
+      message->type = AOS_SSSP_BCBMESSAGE_INVALID;
+      return AOS_FAILURE;
+    }
+  }
+}
+
+/**
+ * @brief   Common outro of the module stack initialization (MSI).
+ * @details This function must be called on failure, success and if MSI is skipped.
+ *
+ * @param[in] msidata   Pointer to the temporary data structure used during MSI.
+ */
+void _msiOutro(aos_ssspmsidata_t* msidata)
+{
+  aosDbgCheck(msidata != NULL);
+
+  // local variables
+  eventmask_t mask = 0;
+
+  // start the internal uptime aggregation
+  chSysLock();
+  aosSysStartUptimeS();
+#if (AMIROOS_CFG_SSSP_MASTER == true)
+  // start toggling S for system synchronization
+  _syncTimerStartS();
+#endif /* (AMIROOS_CFG_SSSP_MASTER == true) */
+  chSysUnlock();
+
+  // reset delay timer
+  chVTIsArmed(&_delayTimer);
+  // unregister delay events
+  mask |= _delayEventListener.events;
+  chEvtUnregister(&_delayEventSource, &_delayEventListener);
+
+#if (AMIROOS_CFG_SSSP_STACK_END != true)
+  // deactivate UP signal
+  apalControlGpioSet(moduleSsspSignalUP(), APAL_GPIO_OFF);
+#endif /* (AMIROOS_CFG_SSSP_STACK_END != true) */
+
+  // reset timeout timer
+  chVTReset(&msidata->timeout.timer);
+  // unregister timeout events
+  mask |= msidata->timeout.eventlistener.events;
+  chEvtUnregister(&msidata->timeout.eventsource, &msidata->timeout.eventlistener);
+
+  // discard any pending timing events
+  chEvtWaitAnyTimeout(mask, TIME_IMMEDIATE);
+
+  // proceed to operation phase
+  aos.sssp.stage = AOS_SSSP_STAGE_OPERATION;
+
+  return;
+}
+
+#endif /* (AMIROOS_CFG_SSSP_MSI == true) */
+
 /******************************************************************************/
 /* EXPORTED FUNCTIONS                                                         */
 /******************************************************************************/
@@ -300,9 +434,6 @@ void aosSsspInit(aos_timestamp_t* system_uptime)
 {
   aosDbgCheck(system_uptime != NULL);
 
-  // local variables
-  apalControlGpioState_t state;
-
 #if (AMIROOS_CFG_SSSP_STARTUP == true)
   // AMiRo-OS has to perform the basic initialization
   aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_1_1;
@@ -311,26 +442,29 @@ void aosSsspInit(aos_timestamp_t* system_uptime)
   aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_2_1;
 #endif /* (AMIROOS_CFG_SSSP_STARTUP == true) */
 
+  // module ID is initialized as 'invalid'
+  aos.sssp.moduleId = AOS_SSSP_MODULEID_INVALID;
+
+#if (AMIROOS_CFG_DBG == true)
   // check all SSSP signals for correct state
-  apalControlGpioGet(&moduleSsspGpioS, &state);
-  aosDbgAssert(state == APAL_GPIO_ON);
-  apalControlGpioGet(&moduleSsspGpioPD, &state);
-  aosDbgAssert(state == APAL_GPIO_OFF);
+  {
+    apalControlGpioState_t state;
+    apalControlGpioGet(moduleSsspSignalS(), &state);
+    aosDbgAssert(state == APAL_GPIO_ON);
+    apalControlGpioGet(moduleSsspSignalPD(), &state);
+    aosDbgAssert(state == APAL_GPIO_OFF);
 #if (AMIROOS_CFG_SSSP_MSI == true)
-#if (AMIROOS_CFG_SSSP_STACK_END != true)
-  apalControlGpioGet(&moduleSsspGpioUP, &state);
-  aosDbgAssert(state == APAL_GPIO_OFF);
-#endif /* (AMIROOS_CFG_SSSP_STACK_END != true) */
 #if (AMIROOS_CFG_SSSP_STACK_START != true)
-  apalControlGpioGet(&moduleSsspGpioDN, &state);
-  aosDbgAssert(state == APAL_GPIO_OFF);
+    apalControlGpioGet(moduleSsspSignalDN(), &state);
+    aosDbgAssert(state == APAL_GPIO_OFF);
 #endif /* (AMIROOS_CFG_SSSP_STACK_START != true) */
+#if (AMIROOS_CFG_SSSP_STACK_END != true)
+    apalControlGpioGet(moduleSsspSignalUP(), &state);
+    aosDbgAssert(state == APAL_GPIO_OFF);
+#endif /* (AMIROOS_CFG_SSSP_END_START != true) */
 #endif /* (AMIROOS_CFG_SSSP_MSI == true) */
-
-#if (AMIROOS_CFG_SSSP_MSI == true)
-  // module ID is initialized as 'invalid'
-  aos.sssp.moduleId = AOS_SSSP_MODULEID_INVALID;
-#endif /* (AMIROOS_CFG_SSSP_MSI == true) */
+  }
+#endif /* (AMIROOS_CFG_DBG == true) */
 
   // initialize static variables
   _uptime = system_uptime;
@@ -342,25 +476,25 @@ void aosSsspInit(aos_timestamp_t* system_uptime)
   _syncskew = 0.0f;
 #endif /* (AMIROOS_CFG_SSSP_MASTER != true) && (AMIROOS_CFG_PROFILE == true) */
   chVTObjectInit(&_delayTimer);
-  chEvtObjectInit(&_eventSourceDelay);
+  chEvtObjectInit(&_delayEventSource);
 
   // signal interrupt setup
-  palSetLineCallback(moduleSsspGpioPD.gpio->line, aosSysGetStdGpioCallback(), &moduleSsspGpioPD.gpio->line);
-  palEnableLineEvent(moduleSsspGpioPD.gpio->line, APAL2CH_EDGE(moduleSsspGpioPD.meta.edge));
+  palSetLineCallback(moduleSsspSignalPD()->gpio->line, aosSysGetStdGpioCallback(), &moduleSsspSignalPD()->gpio->line);
+  palEnableLineEvent(moduleSsspSignalPD()->gpio->line, APAL2CH_EDGE(moduleSsspSignalPD()->meta.edge));
 #if (AMIROOS_CFG_SSSP_MASTER == true)
-  palSetLineCallback(moduleSsspGpioS.gpio->line, aosSysGetStdGpioCallback(), &moduleSsspGpioS.gpio->line);
+  palSetLineCallback(moduleSsspSignalS()->gpio->line, aosSysGetStdGpioCallback(), &moduleSsspSignalS()->gpio->line);
 #else /* (AMIROOS_CFG_SSSP_MASTER == true) */
-  palSetLineCallback(moduleSsspGpioS.gpio->line, _gpioCallbackSSignal, &moduleSsspGpioS.gpio->line);
+  palSetLineCallback(moduleSsspSignalS()->gpio->line, _gpioCallbackSSignal, &moduleSsspSignalS()->gpio->line);
 #endif /* (AMIROOS_CFG_SSSP_MASTER == true) */
-  palEnableLineEvent(moduleSsspGpioS.gpio->line, APAL2CH_EDGE(moduleSsspGpioS.meta.edge));
+  palEnableLineEvent(moduleSsspSignalS()->gpio->line, APAL2CH_EDGE(moduleSsspSignalS()->meta.edge));
 #if (AMIROOS_CFG_SSSP_MSI == true)
 #if (AMIROOS_CFG_SSSP_STACK_START != true)
-  palSetLineCallback(moduleSsspGpioDN.gpio->line, aosSysGetStdGpioCallback(), &moduleSsspGpioDN.gpio->line);
-  palEnableLineEvent(moduleSsspGpioDN.gpio->line, APAL2CH_EDGE(moduleSsspGpioDN.meta.edge));
+  palSetLineCallback(moduleSsspSignalDN()->gpio->line, aosSysGetStdGpioCallback(), &moduleSsspSignalDN()->gpio->line);
+  palEnableLineEvent(moduleSsspSignalDN()->gpio->line, APAL2CH_EDGE(moduleSsspSignalDN()->meta.edge));
 #endif /* (AMIROOS_CFG_SSSP_STACK_START != true) */
 #if (AMIROOS_CFG_SSSP_STACK_END != true)
-  palSetLineCallback(moduleSsspGpioUP.gpio->line, aosSysGetStdGpioCallback(), &moduleSsspGpioUP.gpio->line);
-  palEnableLineEvent(moduleSsspGpioUP.gpio->line, APAL2CH_EDGE(moduleSsspGpioUP.meta.edge));
+  palSetLineCallback(moduleSsspSignalUP()->gpio->line, aosSysGetStdGpioCallback(), &moduleSsspSignalUP()->gpio->line);
+  palEnableLineEvent(moduleSsspSignalUP()->gpio->line, APAL2CH_EDGE(moduleSsspSignalUP()->meta.edge));
 #endif /* (AMIROOS_CFG_SSSP_STACK_END != true) */
 #endif /* (AMIROOS_CFG_SSSP_MSI == true) */
 
@@ -373,7 +507,6 @@ void aosSsspInit(aos_timestamp_t* system_uptime)
  *          The function aosSsspShutdownInit() must be used instead.
  *
  * @param[in]   listener  An optional listener, in case the system has to wait for a specific event.
- * @param[in]   flags     The relevant flags to wait for (mandatory if a listener is given).
  * @param[in]   mask      If the stage transition involves a timer event (handled internally by this function),
  *                        the given input value of this parameter defines the mask to be used for that event.
  *                        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.
@@ -381,7 +514,7 @@ void aosSsspInit(aos_timestamp_t* system_uptime)
  *
  * @return  Status, indicating whether proceeding in the protocol was successful.
  */
-aos_status_t aosSsspProceed(event_listener_t* listener, eventflags_t flags, eventmask_t mask, eventmask_t* received)
+aos_status_t aosSsspProceed(event_listener_t* listener, eventmask_t mask, eventmask_t* received)
 {
   // local variables
 #pragma GCC diagnostic push
@@ -402,23 +535,21 @@ aos_status_t aosSsspProceed(event_listener_t* listener, eventflags_t flags, even
     {
 #if (AMIROOS_CFG_SSSP_MASTER == true)
       aosDbgCheck(listener == NULL);
-      aosDbgCheck(flags == 0);
       aosDbgCheck(mask != 0);
       aosDbgCheck(received != NULL);
 
       // delay execution and deactivate the S signal on success
-      if (_delay(AOS_SSSP_DELAY, mask, (laststage != AOS_SSSP_STAGE_STARTUP_1_1), received) == AOS_SUCCESS) {
-        apalControlGpioSet(&moduleSsspGpioS, APAL_GPIO_OFF);
+      if (_delay(AOS_SSSP_DELAY, mask, received) == AOS_SUCCESS) {
+        apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_OFF);
         nextstage = AOS_SSSP_STAGE_STARTUP_1_2;
       }
 #else /* (AMIROOS_CFG_SSSP_MASTER == true) */
       aosDbgCheck(listener == NULL);
-      aosDbgCheck(flags == 0);
       aosDbgCheck(mask == 0);
       aosDbgCheck(received == NULL);
 
       // deactivate S signal and proceed
-      apalControlGpioSet(&moduleSsspGpioS, APAL_GPIO_OFF);
+      apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_OFF);
       nextstage = AOS_SSSP_STAGE_STARTUP_1_2;
 #endif /* (AMIROOS_CFG_SSSP_MASTER == true) */
       break;
@@ -430,12 +561,11 @@ aos_status_t aosSsspProceed(event_listener_t* listener, eventflags_t flags, even
     case AOS_SSSP_STAGE_STARTUP_1_2:
     {
       aosDbgCheck(listener != NULL);
-      aosDbgCheck(flags != 0);
       aosDbgCheck(mask == listener->events);
       aosDbgCheck(received != NULL);
 
       // wait for the S signal to become inactive and proceed on success
-      if (_waitForS(listener, flags, APAL_GPIO_OFF, received) == AOS_SUCCESS) {
+      if (_waitForS(listener, APAL_GPIO_OFF, received) == AOS_SUCCESS) {
         nextstage = AOS_SSSP_STAGE_STARTUP_1_3;
       }
       break;
@@ -449,24 +579,22 @@ aos_status_t aosSsspProceed(event_listener_t* listener, eventflags_t flags, even
     {
 #if (AMIROOS_CFG_SSSP_MASTER == true)
       aosDbgCheck(listener == NULL);
-      aosDbgCheck(flags == 0);
       aosDbgCheck(mask != 0);
       aosDbgCheck(received != NULL);
 
       // delay execution and deactivate the S signal on success
-      if (_delay(AOS_SSSP_DELAY, mask, (laststage != AOS_SSSP_STAGE_STARTUP_1_3), received) == AOS_SUCCESS) {
-        apalControlGpioSet(&moduleSsspGpioS, APAL_GPIO_ON);
+      if (_delay(AOS_SSSP_DELAY, mask, received) == AOS_SUCCESS) {
+        apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_ON);
         nextstage = AOS_SSSP_STAGE_STARTUP_2_1;
       }
 #else /* (AMIROOS_CFG_SSSP_MASTER == true) */
       aosDbgCheck(listener != NULL);
-      aosDbgCheck(flags != 0);
       aosDbgCheck(mask == listener->events);
       aosDbgCheck(received != NULL);
 
       // wait for the S signal to become active and activate it as well and proceed on success
-      if (_waitForS(listener, flags, APAL_GPIO_ON, received) == AOS_SUCCESS) {
-        apalControlGpioSet(&moduleSsspGpioS, APAL_GPIO_ON);
+      if (_waitForS(listener, APAL_GPIO_ON, received) == AOS_SUCCESS) {
+        apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_ON);
         nextstage = AOS_SSSP_STAGE_STARTUP_2_1;
       }
 #endif /* (AMIROOS_CFG_SSSP_MASTER == true) */
@@ -483,23 +611,23 @@ aos_status_t aosSsspProceed(event_listener_t* listener, eventflags_t flags, even
     {
 #if (AMIROOS_CFG_SSSP_MASTER == true)
       aosDbgCheck(listener == NULL);
-      aosDbgCheck(flags == 0);
       aosDbgCheck(mask != 0);
       aosDbgCheck(received != NULL);
 
       // delay execution and deactivate the S signal on success
-      if (_delay(AOS_SSSP_DELAY, mask, (laststage != AOS_SSSP_STAGE_STARTUP_2_1), received) == AOS_SUCCESS) {
-        apalControlGpioSet(&moduleSsspGpioS, APAL_GPIO_OFF);
+      if (_delay(AOS_SSSP_DELAY, mask, received) == AOS_SUCCESS) {
+        apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_OFF);
         nextstage = AOS_SSSP_STAGE_STARTUP_2_2;
+      } else {
+        aosprintf(".");
       }
 #else /* (AMIROOS_CFG_SSSP_MASTER == true) */
       aosDbgCheck(listener == NULL);
-      aosDbgCheck(flags == 0);
       aosDbgCheck(mask == 0);
       aosDbgCheck(received == NULL);
 
       // deactivate S signal and proceed
-      apalControlGpioSet(&moduleSsspGpioS, APAL_GPIO_OFF);
+      apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_OFF);
       nextstage = AOS_SSSP_STAGE_STARTUP_2_2;
       mask = 0;
 #endif /* (AMIROOS_CFG_SSSP_MASTER == true) */
@@ -513,17 +641,16 @@ aos_status_t aosSsspProceed(event_listener_t* listener, eventflags_t flags, even
     case AOS_SSSP_STAGE_STARTUP_2_2:
     {
       aosDbgCheck(listener != NULL);
-      aosDbgCheck(flags != 0);
       aosDbgCheck(mask == listener->events);
       aosDbgCheck(received != NULL);
 
       // wait for the S signal to become inactive and proceed on success
-      if (_waitForS(listener, flags, APAL_GPIO_OFF, received) == AOS_SUCCESS) {
+      if (_waitForS(listener, APAL_GPIO_OFF, received) == AOS_SUCCESS) {
 #if (AMIROOS_CFG_SSSP_MSI == true)
         nextstage = AOS_SSSP_STAGE_STARTUP_3;
 #else /* (AMIROOS_CFG_SSSP_MSI == true) */
-        chSysLock();
         // start the internal uptime aggregation
+        chSysLock();
         aosSysStartUptimeS();
 #if (AMIROOS_CFG_SSSP_MASTER == true)
         // start toggling S for system synchronization
@@ -536,11 +663,10 @@ aos_status_t aosSsspProceed(event_listener_t* listener, eventflags_t flags, even
       break;
     }
 
-#if (AMIROOS_CFG_SSSP_MSI == true)
-
-      //TODO
-
-#endif /* (AMIROOS_CFG_SSSP_MSI == true) */
+    /*
+     * PLEASE NOTE:
+     * Stage transitions during MSI are not hanlded by thins function but are executed in aosSsspMsi().
+     */
 
     /*
      * Invalid operation.
@@ -560,14 +686,13 @@ aos_status_t aosSsspProceed(event_listener_t* listener, eventflags_t flags, even
     case AOS_SSSP_STAGE_SHUTDOWN_1_2:
     {
       aosDbgCheck(listener == NULL);
-      aosDbgCheck(flags == 0);
       aosDbgCheck(mask == 0);
       aosDbgCheck(received == NULL);
 
       // delay execution
       aosThdUSleep(AOS_SSSP_DELAY);
       // deactivate S signal
-      apalControlGpioSet(&moduleSsspGpioS, APAL_GPIO_OFF);
+      apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_OFF);
       nextstage = AOS_SSSP_STAGE_SHUTDOWN_1_3;
       break;
     }
@@ -580,12 +705,11 @@ aos_status_t aosSsspProceed(event_listener_t* listener, eventflags_t flags, even
     case AOS_SSSP_STAGE_SHUTDOWN_1_3:
     {
       aosDbgCheck(listener != NULL);
-      aosDbgCheck(flags != 0);
       aosDbgCheck(mask == listener->events);
       aosDbgCheck(received != NULL);
 
       // wait for the S signal to become inactive and proceed on success
-      if (_waitForS(listener, flags, APAL_GPIO_OFF, received) == AOS_SUCCESS) {
+      if (_waitForS(listener, APAL_GPIO_OFF, received) == AOS_SUCCESS) {
         nextstage = AOS_SSSP_STAGE_SHUTDOWN_2_1;
       }
       break;
@@ -598,13 +722,12 @@ aos_status_t aosSsspProceed(event_listener_t* listener, eventflags_t flags, even
     case AOS_SSSP_STAGE_SHUTDOWN_2_1:
     {
       aosDbgCheck(listener == NULL);
-      aosDbgCheck(flags == 0);
       aosDbgCheck(mask == 0);
       aosDbgCheck(received != NULL);
 
       // evaluate PD signal
       apalControlGpioState_t pd;
-      apalControlGpioGet(&moduleSsspGpioPD, &pd);
+      apalControlGpioGet(moduleSsspSignalPD(), &pd);
       *received = (pd == APAL_GPIO_ON) ? (eventmask_t)~0 : 0;
       nextstage = AOS_SSSP_STAGE_SHUTDOWN_2_2;
       break;
@@ -616,7 +739,6 @@ aos_status_t aosSsspProceed(event_listener_t* listener, eventflags_t flags, even
     case AOS_SSSP_STAGE_SHUTDOWN_2_2:
     {
       aosDbgCheck(listener == NULL);
-      aosDbgCheck(flags == 0);
       aosDbgCheck(mask == 0);
       aosDbgCheck(received == NULL);
 
@@ -642,6 +764,516 @@ aos_status_t aosSsspProceed(event_listener_t* listener, eventflags_t flags, even
   return status;
 }
 
+#if (AMIROOS_CFG_SSSP_MSI == true) || defined(__DOXYGEN__)
+
+/**
+ * @brief   Initialize MSI data structure.
+ *
+ * @param[out]  msidata       Pointer to the MSI data structure to be initialized.
+ * @param[in]   delayMask     Event maks used for delay events.
+ * @param[in]   timeoutMask   Event mask used for timeout events.
+ * @param[in]   gpioListener  Event listener for GPIO events.
+ */
+void aosSsspMsiInit(aos_ssspmsidata_t* msidata, eventmask_t delayMask, eventmask_t timeoutMask, event_listener_t* gpioListener)
+{
+  aosDbgCheck(msidata != NULL);
+  aosDbgCheck(gpioListener != NULL);
+
+  // register delay events
+  chEvtRegisterMask(&_delayEventSource, &_delayEventListener, delayMask);
+
+  // initialize timeout related data
+  chVTObjectInit(&msidata->timeout.timer);
+  chEvtObjectInit(&msidata->timeout.eventsource);
+  chEvtRegisterMask(&msidata->timeout.eventsource, &msidata->timeout.eventlistener, timeoutMask);
+
+  // set GPIO event information
+  msidata->signals.eventlistener = gpioListener;
+
+  // initialize BCB related data
+  msidata->bcb.lastid = AOS_SSSP_MODULEID_INVALID;
+
+  return;
+}
+
+/**
+ * @brief   Execute module stack initialization (MSI).
+ *
+ * @param[in]   msidata   Data required for MSI.
+ * @param[out]  received  Output variable to store the received event mask to.
+ */
+void aosSsspMsi(aos_ssspmsidata_t* msidata, eventmask_t* received)
+{
+  aosDbgCheck(msidata != NULL);
+  aosDbgCheck(received != NULL);
+
+  /*
+   * execute anything that does not depend on BCB messages or events
+   */
+  switch (aos.sssp.stage) {
+    case AOS_SSSP_STAGE_STARTUP_3:
+    case AOS_SSSP_STAGE_STARTUP_3_1:
+    {
+      aosDbgPrintf(">>> MSI init\n");
+      // setup timeout timer
+      chVTSet(&msidata->timeout.timer, chTimeUS2I(AOS_SSSP_TIMEOUT), _timerCallback, &msidata->timeout.eventsource);
+      // proceed
+#if (AMIROOS_CFG_SSSP_MASTER == true)
+      aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_1_BROADCASTINIT;
+#else /* (AMIROOS_CFG_SSSP_MASTER == true) */
+      aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_1_WAITFORINIT;
+#endif /* (AMIROOS_CFG_SSSP_MASTER == true) */
+      break;
+    }
+
+#if (AMIROOS_CFG_SSSP_MASTER == true)
+    case AOS_SSSP_STAGE_STARTUP_3_1_BROADCASTINIT:
+    {
+      aosDbgPrintf("%u\tsend INIT\t", chVTGetSystemTime());
+      // send init command
+      msidata->bcb.message.type = AOS_SSSP_BCBMESSAGE_MSIINIT;
+      _serializeBcbMessage(msidata->bcb.buffer, msidata->bcb.message);
+      if (moduleSsspBcbTransmit(msidata->bcb.buffer, sizeof(aos_ssspbcbmessage_t)) == AOS_SSSP_BCB_SUCCESS) {
+        aosDbgPrintf("ok\tS+\t");
+        // activate S
+        apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_ON);
+        // restart timeout timer
+        chVTSet(&msidata->timeout.timer, chTimeUS2I(AOS_SSSP_TIMEOUT), _timerCallback, &msidata->timeout.eventsource);
+        // proceed
+#if (AMIROOS_CFG_SSSP_STACK_START == true)
+        aosDbgPrintf("->start\n");
+        aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_2;
+#else /* (AMIROOS_CFG_SSSP_STACK_START == true) */
+        aosDbgPrintf("->count\n");
+        aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_3_WAIT4EVENT;
+#endif /* (AMIROOS_CFG_SSSP_STACK_START == true) */
+      } else {
+        aosDbgPrintf("fail\t->retry\n");
+        // retry in next iteration
+      }
+      break;
+    }
+#endif /* (AMIROOS_CFG_SSSP_MASTER == true) */
+
+#if (AMIROOS_CFG_SSSP_STACK_START == true)
+    case AOS_SSSP_STAGE_STARTUP_3_2:
+    {
+      aosDbgPrintf("%u\tstart\t", chVTGetSystemTime());
+      // set the own module ID
+      aos.sssp.moduleId = 1;
+      // broadcast the new ID
+      msidata->bcb.message.type = AOS_SSSP_BCBMESSAGE_MSIID;
+      msidata->bcb.message.payload.id = aos.sssp.moduleId;
+      aosDbgPrintf("bc ID (%u)\t", msidata->bcb.message.payload.id);
+      _serializeBcbMessage(msidata->bcb.buffer, msidata->bcb.message);
+      if (moduleSsspBcbTransmit(msidata->bcb.buffer, sizeof(aos_ssspbcbmessage_t)) == AOS_SSSP_BCB_SUCCESS) {
+        aosDbgPrintf("ok\t->count\n");
+        // restart timeout timer
+        chVTSet(&msidata->timeout.timer, chTimeUS2I(AOS_SSSP_TIMEOUT), _timerCallback, &msidata->timeout.eventsource);
+        // set delay timer so UP will be activated and S deactivated later
+        chVTSet(&_delayTimer, chTimeUS2I(AOS_SSSP_DELAY), _timerCallback, &_delayEventSource);
+        // store the transmitted ID
+        msidata->bcb.lastid = msidata->bcb.message.payload.id;
+        // proceed
+        aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_3_WAIT4EVENT;
+      } else {
+        aosDbgPrintf("fail\t->retry\n");
+        // retry next iteration
+      }
+      break;
+    }
+#endif /* (AMIROOS_CFG_SSSP_STACK_START == true) */
+
+    case AOS_SSSP_STAGE_STARTUP_3_3_BROADCASTID:
+    {
+      // broadcast ID
+      msidata->bcb.message.type = AOS_SSSP_BCBMESSAGE_MSIID;
+      msidata->bcb.message.payload.id = aos.sssp.moduleId;
+      aosDbgPrintf("%u\tbc ID (%u)\t", chVTGetSystemTime(), msidata->bcb.message.payload.id);
+      _serializeBcbMessage(msidata->bcb.buffer, msidata->bcb.message);
+      if (moduleSsspBcbTransmit(msidata->bcb.buffer, sizeof(aos_ssspbcbmessage_t)) == AOS_SSSP_BCB_SUCCESS) {
+        aosDbgPrintf("ok->count\n");
+        // restart timeout timer
+        chVTSet(&msidata->timeout.timer, chTimeUS2I(AOS_SSSP_TIMEOUT), _timerCallback, &msidata->timeout.eventsource);
+        // set delay timer so UP will be activated and S deactivated later
+        chVTSet(&_delayTimer, chTimeUS2I(AOS_SSSP_DELAY), _timerCallback, &_delayEventSource);
+        // store the transmitted ID
+        msidata->bcb.lastid = msidata->bcb.message.payload.id;
+        // return to receiving
+        aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_3_WAIT4EVENT;
+      } else {
+        aosDbgPrintf("fail\t->retry\n");
+        // retry next iteration
+      }
+      break;
+    }
+
+    case AOS_SSSP_STAGE_STARTUP_3_4_ABORTION_INIT:
+    {
+      aosDbgPrintf("%u\tabort\t", chVTGetSystemTime());
+      // reset timeout timer
+      chVTReset(&msidata->timeout.timer);
+      // transmit abort message
+      msidata->bcb.message.type = AOS_SSSP_BCBMESSAGE_MSIABORT;
+      _serializeBcbMessage(msidata->bcb.buffer, msidata->bcb.message);
+      if (moduleSsspBcbTransmit(msidata->bcb.buffer, sizeof(aos_ssspbcbmessage_t)) == AOS_SSSP_BCB_SUCCESS) {
+        aosDbgPrintf("ok\tS-\t->sync\n");
+        // deactivate S
+        apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_OFF);
+        // proceed
+        aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_4_ABORTION_SYNC;
+      } else {
+        aosDbgPrintf("fail\t->retry\n");
+        // retry next iteration
+      }
+      break;
+    }
+
+    default:
+    {
+      // all other stages depend on events or BCB messages and are thus handled below
+      break;
+    }
+  }
+
+  /*
+   * handle BCB messages
+   */
+  msidata->bcb.status = moduleSsspBcbReceive(msidata->bcb.buffer, sizeof(aos_ssspbcbmessage_t));
+  switch (msidata->bcb.status) {
+
+    /* VALID BCB MESSAGE
+     * A message was received via BCB that seems to be plausible.
+     * The first BCB message initiates the sequence once.
+     * During MSI an arbitrary number of IDs will be received.
+     * Abort messages can be received at any time.
+     */
+    case AOS_SSSP_BCB_SUCCESS:
+    {
+      aosDbgPrintf("%u\tBCB\t", chVTGetSystemTime());
+      // deserialize message and handle types differently
+      _deserializeBcbMessage(&msidata->bcb.message, msidata->bcb.buffer);
+      switch (msidata->bcb.message.type) {
+        // initialization message
+        case AOS_SSSP_BCBMESSAGE_MSIINIT:
+        {
+#if (AMIROOS_CFG_SSSP_MASTER == true)
+          aosDbgPrintf("INIT\t->abort\n");
+          // initiate abortion
+          aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_4_ABORTION_INIT;
+#else /* (AMIROOS_CFG_SSSP_MASTER == true) */
+          aosDbgPrintf("INIT\t");
+          // check for correct SSSP stage
+          if (aos.sssp.stage == AOS_SSSP_STAGE_STARTUP_3_1_WAITFORINIT) {
+            aosDbgPrintf("S+\t");
+            // activate S
+            apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_ON);
+            // restart timeout timer
+            chVTSet(&msidata->timeout.timer, chTimeUS2I(AOS_SSSP_TIMEOUT), _timerCallback, &msidata->timeout.eventsource);
+            // proceed
+#if (AMIROOS_CFG_SSSP_STACK_START == true)
+            aosDbgPrintf("->start\n");
+            aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_2;
+#else /* (AMIROOS_CFG_SSSP_STACK_START == true) */
+            aosDbgPrintf("->count\n");
+            aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_3_WAIT4EVENT;
+#endif /* (AMIROOS_CFG_SSSP_STACK_START == true) */
+          } else {
+            aosDbgPrintf("->abort\n");
+            // initiate abortion
+            aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_4_ABORTION_INIT;
+          }
+#endif /* (AMIROOS_CFG_SSSP_MASTER == true) */
+          break;
+        }
+        // ID message
+        case AOS_SSSP_BCBMESSAGE_MSIID:
+        {
+          aosDbgPrintf("ID (%u)\t", msidata->bcb.message.payload.id);
+          // check for correct stage and whether ID was increased
+          if (aos.sssp.stage == AOS_SSSP_STAGE_STARTUP_3_3_WAIT4EVENT &&
+              msidata->bcb.message.payload.id > msidata->bcb.lastid) {
+            aosDbgPrintf("ok\n");
+            // restart timeout timer
+            chVTSet(&msidata->timeout.timer, chTimeUS2I(AOS_SSSP_TIMEOUT), _timerCallback, &msidata->timeout.eventsource);
+            // store ID
+            msidata->bcb.lastid = msidata->bcb.message.payload.id;
+          } else {
+            aosDbgPrintf("fail\t->abort\n");
+            // initiate abortion
+            aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_4_ABORTION_INIT;
+          }
+          break;
+        }
+        // abort message
+        case AOS_SSSP_BCBMESSAGE_MSIABORT:
+        {
+          aosDbgPrintf("ABORT\tS-\t->sync\n");
+          // reset timeout timer
+          chVTReset(&msidata->timeout.timer);
+          // deactivate S
+          apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_OFF);
+          // proceed to abort synchronization
+          aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_4_ABORTION_SYNC;
+          break;
+        }
+        // invalid message
+        default:
+        {
+          aosDbgPrintf("invalid\t->abort\n");
+          // initiate abortion
+          aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_4_ABORTION_INIT;
+          break;
+        }
+      }
+      return;
+    }
+
+    /* INVALID BCB MESSAGE
+     * An obviously invalid message was received via BCB.
+     */
+    case AOS_SSSP_BCB_INVALIDMSG:
+    {
+      // error but ignore
+      aosDbgPrintf("WARNING: unknown message received via BCB\n");
+      break;
+    }
+
+    /* NO BCB MESSAGE
+     * No message was received via BCB at all.
+     */
+    case AOS_SSSP_BCB_ERROR:
+    {
+      // do nothing and proceed
+      break;
+    }
+  }
+
+  /*
+   * handle events
+   */
+  *received = chEvtWaitOneTimeout(ALL_EVENTS, TIME_IMMEDIATE);
+  /* TIMEOUT EVENT
+   * Timeouts can occur at any time during MSI after they have been initialized.
+   * As soon as the module has made it to the 3.4 completion stage, there will be no more timeouts, though.
+   */
+  if (*received & msidata->timeout.eventlistener.events) {
+    aosDbgPrintf("%u\ttimeout\t", chVTGetSystemTime());
+    // special cases
+    if (aos.sssp.stage == AOS_SSSP_STAGE_STARTUP_3_1_WAITFORINIT ||
+        aos.sssp.stage == AOS_SSSP_STAGE_STARTUP_3_4_COMPLETION) {
+      // master did not initiate the sequence
+      if (aos.sssp.stage == AOS_SSSP_STAGE_STARTUP_3_1_WAITFORINIT) {
+        aosDbgPrintf("no init\t->operation\n");
+        // invalidate module ID
+        aos.sssp.moduleId = AOS_SSSP_MODULEID_INVALID;
+        aosDbgPrintf("<<< MSI skipped\n");
+      }
+      // no abort messages received after completion
+      else /* if (aos.sssp.stage == AOS_SSSP_STAGE_STARTUP_3_4_COMPLETION) */ {
+        aosDbgPrintf("success\t->operation\n");
+        aosDbgPrintf("<<< MSI completed\n");
+      }
+      // cleanup and proceed to operation phase
+      _msiOutro(msidata);
+    }
+    // general timeout
+    else {
+      aosDbgPrintf("->abort\n");
+      // initiate active abort
+      aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_4_ABORTION_INIT;
+    }
+    // clear event
+    chEvtGetAndClearFlags(&msidata->timeout.eventlistener);
+    *received &= ~(msidata->timeout.eventlistener.events);
+  }
+  /* DELAY EVENT
+   * Delays are only used to toggle the UP signal.
+   */
+  else if (*received & _delayEventListener.events) {
+    aosDbgPrintf("%u\tdelay\t", chVTGetSystemTime());
+#if (AMIROOS_CFG_SSSP_STACK_END == true)
+    apalControlGpioState_t s;
+    aosDbgPrintf("S-\t");
+    // deactivate S
+    apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_OFF);
+    // verify deactivation
+    apalControlGpioGet(moduleSsspSignalS(), &s);
+    if (s == APAL_GPIO_OFF) {
+      aosDbgPrintf("ok\t->done\n");
+      // set the timeout timer so no abort messages are missed
+      chVTSet(&msidata->timeout.timer, chTimeUS2I(AOS_SSSP_TIMEOUT), _timerCallback, &msidata->timeout.eventsource);
+      // proceed to the completion stage
+      aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_4_COMPLETION;
+    } else {
+      aosDbgPrintf("fail\t->abort\n");
+      // initiate active abort
+      aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_4_ABORTION_INIT;
+    }
+#else /* (AMIROOS_CFG_SSSP_STACK_END == true) */
+    apalControlGpioState_t s;
+    // read the current state of the UP signal
+    apalControlGpioGet(moduleSsspSignalUP(), &s);
+    if (s == APAL_GPIO_OFF) {
+      aosDbgPrintf("UP+ & S-\n");
+      // activate UP in order to trigger the next module
+      apalControlGpioSet(moduleSsspSignalUP(), APAL_GPIO_ON);
+      // deactivate S
+      apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_OFF);
+      // set the delay timer so the UP signal will get deactivated again later
+      chVTSet(&_delayTimer, chTimeUS2I(AOS_SSSP_DELAY), _timerCallback, &_delayEventSource);
+    } else {
+      aosDbgPrintf("UP-\n");
+      // deactvate UP
+      apalControlGpioSet(moduleSsspSignalUP(), APAL_GPIO_OFF);
+    }
+#endif /* (AMIROOS_CFG_SSSP_STACK_END == true) */
+    // clear event
+    chEvtGetAndClearFlags(&_delayEventListener);
+    *received &= ~(_delayEventListener.events);
+  }
+  /* GPIO EVENT
+   * GPIO events can occurr at any time, but only DN and S events are expected.
+   * DN may be activated only once per module to trigger the counting process and is deactivated briefly after activation.
+   * S must only deactivate when MSI is comleted by the last module in the stack.
+   */
+  else if (*received & msidata->signals.eventlistener->events) {
+    aosDbgPrintf("%u\tGPIO\t", chVTGetSystemTime());
+    apalControlGpioState_t s;
+    // fetch event flags
+    eventflags_t flags = chEvtGetAndClearFlags(msidata->signals.eventlistener);
+#if (AMIROOS_CFG_SSSP_STACK_START != true)
+    // if the DN signal was triggered
+    if (flags & moduleSsspEventflagDN()) {
+      // read the signal state
+      apalControlGpioGet(moduleSsspSignalDN(), &s);
+      // rising edge
+      if (s == APAL_GPIO_ON) {
+        aosDbgPrintf("+DN\t");
+        // Correct SSSP stage and no ID assigned yet?
+        if (aos.sssp.stage == AOS_SSSP_STAGE_STARTUP_3_3_WAIT4EVENT &&
+            aos.sssp.moduleId == AOS_SSSP_MODULEID_INVALID) {
+          // set the own module ID
+          aos.sssp.moduleId = msidata->bcb.lastid + 1;
+          aosDbgPrintf("set ID (%u)\t->bc ID\n", aos.sssp.moduleId);
+          // proceed to broadcasting
+          aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_3_BROADCASTID;
+        }
+        // incorrect SSSP stage or ID already assigned (triggered for a second time)
+        else {
+          aosDbgPrintf("->abort\n");
+          // initiate active abort
+          aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_4_ABORTION_INIT;
+        }
+      }
+      // falling egde
+      else {
+        aosDbgPrintf("-DN\n");
+        // ignored
+      }
+      // clear DN flags
+      flags &= ~moduleSsspEventflagDN();
+    }
+#endif /* (AMIROOS_CFG_SSSP_STACK_START != true) */
+#if (AMIROOS_CFG_SSSP_STACK_END != true)
+    // if the UP signal was triggered
+    if (flags & moduleSsspEventflagUP()) {
+      /*
+       * The UP signal is acting as output only.
+       * Any events resulting from toggling the signal are thus ignored.
+       */
+      aosDbgPrintf("?UP\n");
+      // clear UP flags
+      flags &= ~moduleSsspEventflagUP();
+    }
+#endif /* (AMIROOS_CFG_SSSP_STACK_END != true) */
+    // if the S signal was triggered
+    if (flags & moduleSsspEventflagS()) {
+      // read the signal state
+      apalControlGpioGet(moduleSsspSignalS(), &s);
+      // rising edge
+      if (s == APAL_GPIO_ON) {
+        aosDbgPrintf("+S\n");
+        // ignored
+      }
+      // falling edge
+      else {
+        aosDbgPrintf("-S\t");
+        // special case
+        if (aos.sssp.stage == AOS_SSSP_STAGE_STARTUP_3_4_ABORTION_SYNC) {
+          aosDbgPrintf("->operation\n");
+          // invalidate module ID
+          aos.sssp.moduleId = AOS_SSSP_MODULEID_INVALID;
+          // proceed
+          aosDbgPrintf("<<< MSI aborted\n");
+          _msiOutro(msidata);
+        }
+#if (AMIROOS_CFG_SSSP_STACK_END == true)
+        // Correct SSSP stage?
+        else if (aos.sssp.stage == AOS_SSSP_STAGE_STARTUP_3_4_COMPLETION) {
+          aosDbgPrintf("ok\n");
+          // ignored
+        } else {
+          aosDbgPrintf("->abort\n");
+          // initialize abortion
+          aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_4_ABORTION_INIT;
+        }
+#else /* (AMIROOS_CFG_SSSP_STACK_END == true) */
+        // Correct SSSP stage and ID assigned?
+        else if (aos.sssp.stage == AOS_SSSP_STAGE_STARTUP_3_3_WAIT4EVENT &&
+            aos.sssp.moduleId != AOS_SSSP_MODULEID_INVALID) {
+          aosDbgPrintf("->done\n");
+          // set the timeout timer so no abort messages are missed
+          chVTSet(&msidata->timeout.timer, chTimeUS2I(AOS_SSSP_TIMEOUT), _timerCallback, &msidata->timeout.eventsource);
+          // proceed to the completion stage
+          aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_4_COMPLETION;
+        } else {
+          aosDbgPrintf("->abort\n");
+          // initiate abortion
+          aos.sssp.stage = AOS_SSSP_STAGE_STARTUP_3_4_ABORTION_INIT;
+        }
+#endif /* (AMIROOS_CFG_SSSP_STACK_END == true) */
+      }
+      // clear S flags
+      flags &= ~moduleSsspEventflagS();
+    }
+    // any further flags set?
+    if (flags) {
+      aosDbgPrintf("0x%08X\n", flags);
+      // reassign remaining flags and do not clear event mask
+      msidata->signals.eventlistener->flags |= flags;
+    } else {
+      // clear event
+      *received &= ~(msidata->signals.eventlistener->events);
+    }
+  }
+  /* OTHER EVENT
+   * Any other events may occur as well but are not handled by this function
+   */
+  else if (*received != 0){
+    aosDbgPrintf("%u\tOTHER\t0x%08X\n", chVTGetSystemTime(), *received);
+    // do not clear the event mask
+  }
+
+  return;
+}
+
+#endif /* (AMIROOS_CFG_SSSP_MSI == true) */
+
+#if ((AMIROOS_CFG_SSSP_MASTER != true) && (AMIROOS_CFG_PROFILE == true)) || defined(__DOXYGEN__)
+
+/**
+ * @brief   Retreive the offset between local clock and system synchronization signal.
+ *
+ * @return
+ */
+inline float aosSsspGetSyncSkew(void)
+{
+  return _syncskew;
+}
+
+#endif /* (AMIROOS_CFG_SSSP_MASTER != true) && (AMIROOS_CFG_PROFILE == true) */
+
 /**
  * @brief   Leave the operation pahse and initiate or acknowledge shutdown.
  *
@@ -656,7 +1288,7 @@ void aosSsspShutdownInit(bool active)
 
   // activate PD if this was an active shutdown initiation
   if (active) {
-    apalControlGpioSet(&moduleSsspGpioPD, APAL_GPIO_ON);
+    apalControlGpioSet(moduleSsspSignalPD(), APAL_GPIO_ON);
   }
 
 #if (AMIROOS_CFG_SSSP_MASTER == true)
@@ -665,7 +1297,7 @@ void aosSsspShutdownInit(bool active)
 #endif /* (AMIROOS_CFG_SSSP_MASTER == true) */
 
   // activate S
-  apalControlGpioSet(&moduleSsspGpioS, APAL_GPIO_ON);
+  apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_ON);
 
   // proceed in the shutdown phase
   aos.sssp.stage = AOS_SSSP_STAGE_SHUTDOWN_1_2;
@@ -690,9 +1322,9 @@ void aosSsspShutdownBroadcastIdentifier(unsigned int identifier)
       aosThdUSleep(AOS_SSSP_DELAY);
 
       // activate S for one AOS_SSSP_DELAY.
-      apalControlGpioSet(&moduleSsspGpioS, APAL_GPIO_ON);
+      apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_ON);
       aosThdUSleep(AOS_SSSP_DELAY);
-      apalControlGpioSet(&moduleSsspGpioS, APAL_GPIO_OFF);
+      apalControlGpioSet(moduleSsspSignalS(), APAL_GPIO_OFF);
     }
   }
 
@@ -728,8 +1360,8 @@ eventmask_t aosSsspShutdownWaitForIdentifierPulse(event_listener_t* gpiolistener
 
   // arm the timer once
   if (!chVTIsArmed(&_delayTimer)) {
-    chEvtRegisterMask(&_eventSourceDelay, &_eventListenerDelay, timermask);
-    chVTSet(&_delayTimer, chTimeUS2I(AOS_SSSP_TIMEOUT), _timerCallback, &_eventSourceDelay);
+    chEvtRegisterMask(&_delayEventSource, &_delayEventListener, timermask);
+    chVtSet(&_delayTimer, chTimeUS2I(AOS_SSSP_TIMEOUT), _timerCallback, &_delayEventSource);
   }
 
   // wait for any event to occur (do not apply any filters in order not to miss any events)
@@ -739,23 +1371,22 @@ eventmask_t aosSsspShutdownWaitForIdentifierPulse(event_listener_t* gpiolistener
   if (mask & gpiolistener->events) {
     // retreive flags without clearing them
     flags = gpiolistener->flags;
-    apalControlGpioGet(&moduleSsspGpioS, &sstate);
+    apalControlGpioGet(moduleSsspSignalS(), &sstate);
     if (flags == sflags) {
-      apalControlGpioGet(&moduleSsspGpioS, &sstate);
+      apalControlGpioGet(moduleSsspSignalS(), &sstate);
       // if this was the end of a pulse
       if (sstate == APAL_GPIO_OFF) {
         // restart the timer
-        chVTReset(&_delayTimer);
-        chVTSet(&_delayTimer, chTimeUS2I(AOS_SSSP_TIMEOUT), _timerCallback, &_eventSourceDelay);
+        chVtSet(&_delayTimer, chTimeUS2I(AOS_SSSP_TIMEOUT), _timerCallback, &_delayEventSource);
         // increment the identifier
         ++(*identifier);
       }
     }
   }
   // timer event
-  else if (mask & _eventListenerDelay.events) {
+  else if (mask & _delayEventListener.events) {
     // unregister event
-    chEvtUnregister(&_eventSourceDelay, &_eventListenerDelay);
+    chEvtUnregister(&_delayEventSource, &_delayEventListener);
   }
   // any further events must be handled externally
 
@@ -764,20 +1395,6 @@ eventmask_t aosSsspShutdownWaitForIdentifierPulse(event_listener_t* gpiolistener
 
 #endif /* (AMIROOS_CFG_SSSP_SHUTDOWN == true) */
 
-#if ((AMIROOS_CFG_SSSP_MASTER != true) && (AMIROOS_CFG_PROFILE == true)) || defined(__DOXYGEN__)
-
-/**
- * @brief   Retreive the offset between local clock and system synchronization signal.
- *
- * @return
- */
-float aosSsspGetSyncSkew(void)
-{
-  return _syncskew;
-}
-
-#endif /* (AMIROOS_CFG_SSSP_MASTER != true) && (AMIROOS_CFG_PROFILE == true) */
-
 #endif /* (AMIROOS_CFG_SSSP_ENABLE == true) */
 
 /** @} */
