commit c218345a0ad12a54f704b665ed16c7eef1d7b227
Author: Thomas Schöpping <tschoepp@cit-ec.uni-bielefeld.de>
Date:   Thu Oct 31 16:26:02 2019 +0100

    SSSP system synchronization is now handled in aos_sssp.h/.c

diff --git a/core/src/aos_sssp.c b/core/src/aos_sssp.c
index c058862..8f82143 100644
--- a/core/src/aos_sssp.c
+++ b/core/src/aos_sssp.c
@@ -32,6 +32,15 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 /* LOCAL DEFINITIONS                                                          */
 /******************************************************************************/
 
+#if ((AMIROOS_CFG_SSSP_MASTER != true) && (AMIROOS_CFG_PROFILE == true)) || defined(__DOXYGEN__)
+
+/**
+ * @brief   Weighting factor for smoothing the @p _syncskew value.
+ */
+#define SYNCSKEW_SMOOTHFACTOR                   (0.1f / AOS_SYSTEM_TIME_RESOLUTION)
+
+#endif /* (AMIROOS_CFG_SSSP_MASTER != true) && (AMIROOS_CFG_PROFILE == true) */
+
 /******************************************************************************/
 /* EXPORTED VARIABLES                                                         */
 /******************************************************************************/
@@ -45,6 +54,34 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 /******************************************************************************/
 
 /**
+ * @brief   Pointer to the system uptime.
+ */
+static aos_timestamp_t* _uptime;
+
+#if (AMIROOS_CFG_SSSP_MASTER == true) || defined(__DOXYGEN__)
+
+/**
+ * @brief   Timer to drive the S signal for system wide time synchronization during operation phase.
+ */
+static virtual_timer_t _synctimer;
+
+/**
+ * @brief   Last uptime of system wide time synchronization.
+ */
+static aos_timestamp_t _synctime;
+
+#endif /* (AMIROOS_CFG_SSSP_MASTER == true) */
+
+#if ((AMIROOS_CFG_SSSP_MASTER != true) && (AMIROOS_CFG_PROFILE == true)) || defined(__DOXYGEN__)
+
+/**
+ * @brief   Offset between local clock and system wide synchronization signal.
+ */
+static float _syncskew;
+
+#endif /* (AMIROOS_CFG_SSSP_MASTER != true) && (AMIROOS_CFG_PROFILE == true) */
+
+/**
  * @brief   A timer event based delays.
  */
 static virtual_timer_t _delayTimer;
@@ -63,6 +100,112 @@ static event_listener_t _eventListenerDelay;
 /* LOCAL FUNCTIONS                                                            */
 /******************************************************************************/
 
+#if (AMIROOS_CFG_SSSP_MASTER != true) || defined(__DOXYGEN__)
+
+/**
+ * @brief   Callback function for the Sync signal interrupt.
+ *
+ * @param[in] args   Pointer to the GPIO line identifier.
+ */
+static void _gpioCallbackSSignal(void *args)
+{
+  aosDbgCheck((args != NULL) && (*((ioline_t*)args) != PAL_NOLINE) && (PAL_PAD(*((ioline_t*)args)) < sizeof(eventflags_t) * 8));
+
+  apalControlGpioState_t s;
+  aos_timestamp_t t;
+
+  chSysLockFromISR();
+
+  // if the system is in operation phase
+  if (aos.sssp.stage == AOS_SSSP_STAGE_OPERATION) {
+    // read signal S
+    apalControlGpioGet(&moduleSsspGpioS, &s);
+    // if S was toggled from on to off
+    if (s == APAL_GPIO_OFF) {
+      // get current uptime
+      aosSysGetUptimeX(&t);
+      // align the uptime with the synchronization period
+      t %= AMIROOS_CFG_SSSP_SYSSYNCPERIOD;
+      if (t < AMIROOS_CFG_SSSP_SYSSYNCPERIOD / 2) {
+        *_uptime -= t;
+#if (AMIROOS_CFG_PROFILE == true)
+        _syncskew = ((1.0f - SYNCSKEW_SMOOTHFACTOR) * _syncskew) + (SYNCSKEW_SMOOTHFACTOR * t);
+#endif /* (AMIROOS_CFG_PROFILE == true) */
+      } else {
+        t = AMIROOS_CFG_SSSP_SYSSYNCPERIOD - t;
+        *_uptime += t;
+#if (AMIROOS_CFG_PROFILE == true)
+        _syncskew = ((1.0f - SYNCSKEW_SMOOTHFACTOR) * _syncskew) - (SYNCSKEW_SMOOTHFACTOR * t);
+#endif /* (AMIROOS_CFG_PROFILE == true) */
+      }
+    }
+  }
+
+  // broadcast event
+  chEvtBroadcastFlagsI(&aos.events.gpio, AOS_GPIOEVENT_FLAG(PAL_PAD(*((ioline_t*)args))));
+  chSysUnlockFromISR();
+
+  return;
+}
+
+#endif /* (AMIROOS_CFG_SSSP_MASTER != true) */
+
+#if (AMIROOS_CFG_SSSP_MASTER == true) || defined (__DOXYGEN__)
+
+/**
+ * @brief   Periodic system synchronization callback function.
+ * @details Toggles the SYS_SYNC signal and reconfigures the system synchronization timer.
+ *
+ * @param[in] par   Unused parameters.
+ */
+static void _syncTimerCallback(void* par)
+{
+  (void)par;
+
+  apalControlGpioState_t state;
+  aos_timestamp_t uptime;
+
+  chSysLockFromISR();
+  // toggle and read signal S
+  apalGpioToggle(moduleSsspGpioS.gpio);
+  apalControlGpioGet(&moduleSsspGpioS, &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);
+  }
+  // if S was toggled from on to off
+  else /* if (state == APAL_GPIO_OFF) */ {
+    // reconfigure the timer (lazy)
+    chVTSetI(&_synctimer, chTimeUS2I(AMIROOS_CFG_SSSP_SYSSYNCPERIOD / 2), _syncTimerCallback, NULL);
+  }
+  chSysUnlockFromISR();
+
+  return;
+}
+
+/**
+ * @brief   Start the timer that toggles S for synchronization of the system.
+ * @note    Must be called from a locked context.
+ */
+static inline void _syncTimerStartS(void)
+{
+  chDbgCheckClassS();
+
+  // start synchronization timer
+  // The first iteration of the timer is set to the next 'center' of a 'slice'.
+  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);
+
+  return;
+}
+
+#endif /* (AMIROOS_CFG_SSSP_MASTER == true) */
+
 /**
  * @brief   General callback function to be used for any local timers.
  *
@@ -153,8 +296,10 @@ static inline aos_status_t _delay(uint32_t dt, eventmask_t mask, bool arm_timer,
 /**
  * @brief   Initialize all SSSP related data.
  */
-void aosSsspInit(void)
+void aosSsspInit(aos_timestamp_t* system_uptime)
 {
+  aosDbgCheck(system_uptime != NULL);
+
   // local variables
   apalControlGpioState_t state;
 
@@ -171,6 +316,7 @@ void aosSsspInit(void)
   aosDbgAssert(state == APAL_GPIO_ON);
   apalControlGpioGet(&moduleSsspGpioPD, &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);
@@ -179,6 +325,7 @@ void aosSsspInit(void)
   apalControlGpioGet(&moduleSsspGpioDN, &state);
   aosDbgAssert(state == APAL_GPIO_OFF);
 #endif /* (AMIROOS_CFG_SSSP_STACK_START != true) */
+#endif /* (AMIROOS_CFG_SSSP_MSI == true) */
 
 #if (AMIROOS_CFG_SSSP_MSI == true)
   // module ID is initialized as 'invalid'
@@ -186,14 +333,44 @@ void aosSsspInit(void)
 #endif /* (AMIROOS_CFG_SSSP_MSI == true) */
 
   // initialize static variables
+  _uptime = system_uptime;
+#if (AMIROOS_CFG_SSSP_MASTER == true)
+  chVTObjectInit(&_synctimer);
+  _synctime = 0;
+#endif /* (AMIROOS_CFG_SSSP_MASTER == true) */
+#if (AMIROOS_CFG_SSSP_MASTER != true) && (AMIROOS_CFG_PROFILE == true)
+  _syncskew = 0.0f;
+#endif /* (AMIROOS_CFG_SSSP_MASTER != true) && (AMIROOS_CFG_PROFILE == true) */
   chVTObjectInit(&_delayTimer);
   chEvtObjectInit(&_eventSourceDelay);
 
+  // signal interrupt setup
+  palSetLineCallback(moduleSsspGpioPD.gpio->line, aosSysGetStdGpioCallback(), &moduleSsspGpioPD.gpio->line);
+  palEnableLineEvent(moduleSsspGpioPD.gpio->line, APAL2CH_EDGE(moduleSsspGpioPD.meta.edge));
+#if (AMIROOS_CFG_SSSP_MASTER == true)
+  palSetLineCallback(moduleSsspGpioS.gpio->line, aosSysGetStdGpioCallback(), &moduleSsspGpioS.gpio->line);
+#else /* (AMIROOS_CFG_SSSP_MASTER == true) */
+  palSetLineCallback(moduleSsspGpioS.gpio->line, _gpioCallbackSSignal, &moduleSsspGpioS.gpio->line);
+#endif /* (AMIROOS_CFG_SSSP_MASTER == true) */
+  palEnableLineEvent(moduleSsspGpioS.gpio->line, APAL2CH_EDGE(moduleSsspGpioS.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));
+#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));
+#endif /* (AMIROOS_CFG_SSSP_STACK_END != true) */
+#endif /* (AMIROOS_CFG_SSSP_MSI == true) */
+
   return;
 }
 
 /**
  * @brief   Proceed to the next SSSP stage.
+ * @note    Calling this function when in operation phase is invalid.
+ *          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).
@@ -331,6 +508,7 @@ aos_status_t aosSsspProceed(event_listener_t* listener, eventflags_t flags, even
 
     /*
      * Wait for the S signal to become inactive.
+     * When proceeding to operation phase, the master starts toggling S for synchronization
      */
     case AOS_SSSP_STAGE_STARTUP_2_2:
     {
@@ -344,6 +522,14 @@ aos_status_t aosSsspProceed(event_listener_t* listener, eventflags_t flags, even
 #if (AMIROOS_CFG_SSSP_MSI == true)
         nextstage = AOS_SSSP_STAGE_STARTUP_3;
 #else /* (AMIROOS_CFG_SSSP_MSI == true) */
+        chSysLock();
+        // start the internal uptime aggregation
+        aosSysStartUptimeS();
+#if (AMIROOS_CFG_SSSP_MASTER == true)
+        // start toggling S for system synchronization
+        _syncTimerStartS();
+#endif /* (AMIROOS_CFG_SSSP_MASTER == true) */
+        chSysUnlock();
         nextstage = AOS_SSSP_STAGE_OPERATION;
 #endif /* (AMIROOS_CFG_SSSP_MSI == true) */
       }
@@ -357,6 +543,16 @@ aos_status_t aosSsspProceed(event_listener_t* listener, eventflags_t flags, even
 #endif /* (AMIROOS_CFG_SSSP_MSI == true) */
 
     /*
+     * Invalid operation.
+     * Shutdon must be initiatid via the aosSsspShutdownInit() function.
+     */
+    case AOS_SSSP_STAGE_OPERATION:
+    {
+      aosDbgAssertMsg(false, "in order to exit operation phase, aosSsspShutdownInit() function must be used");
+      break;
+    }
+
+    /*
      * Delay execution by one perion AOS_SSSP_DELAY, deactivate the SYNC signal and proceed.
      * NOTE: Actually only the module that initiated the shutdown has to delay execution here.
      *       For the sake of simlicity though, each module delays execution.
@@ -446,11 +642,32 @@ aos_status_t aosSsspProceed(event_listener_t* listener, eventflags_t flags, even
   return status;
 }
 
-void aosSsspShutdownInit(void)
+/**
+ * @brief   Leave the operation pahse and initiate or acknowledge shutdown.
+ *
+ * @param[in] active  Flag, indicating whether the shutdon shall be activeliy initiated (true) or a passive request was received (false).
+ */
+void aosSsspShutdownInit(bool active)
 {
-  // activate S signal
-  apalControlGpioSet(&moduleSsspGpioS, APAL_GPIO_ON);
+  aosDbgAssert(aos.sssp.stage == AOS_SSSP_STAGE_OPERATION);
+
   // proceed to shutdown phase
+  aos.sssp.stage = AOS_SSSP_STAGE_SHUTDOWN_1_1;
+
+  // activate PD if this was an active shutdown initiation
+  if (active) {
+    apalControlGpioSet(&moduleSsspGpioPD, APAL_GPIO_ON);
+  }
+
+#if (AMIROOS_CFG_SSSP_MASTER == true)
+  // stop toggling S
+  chVTReset(&_synctimer);
+#endif /* (AMIROOS_CFG_SSSP_MASTER == true) */
+
+  // activate S
+  apalControlGpioSet(&moduleSsspGpioS, APAL_GPIO_ON);
+
+  // proceed in the shutdown phase
   aos.sssp.stage = AOS_SSSP_STAGE_SHUTDOWN_1_2;
 
   return;
@@ -547,6 +764,20 @@ 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) */
 
 /** @} */
