Write DC system time offsets right after slave scan / config change. Wait for DC clock discipline.
authorFlorian Pose <fp@igh-essen.com>
Thu, 06 May 2010 11:42:52 +0200
changeset 1925 29161abef052
parent 1924 2917b262554b
child 1926 b2e097ff4b00
Write DC system time offsets right after slave scan / config change. Wait for DC clock discipline.
TODO
master/fsm_master.c
master/fsm_slave_config.c
master/master.c
master/master.h
--- a/TODO	Thu May 06 11:41:25 2010 +0200
+++ b/TODO	Thu May 06 11:42:52 2010 +0200
@@ -41,6 +41,7 @@
 * Log SoE IDNs with real name ([SP]-x-yyyy).
 * Output SoE IDN configurations in 'ethercat config'.
 * Fix casting away constness during expected WC calculation.
+* Only set system time offset, if application time is present.
 * Read AL status code on spontaneous state change.
 
 Future issues:
--- a/master/fsm_master.c	Thu May 06 11:41:25 2010 +0200
+++ b/master/fsm_master.c	Thu May 06 11:42:52 2010 +0200
@@ -46,6 +46,12 @@
 
 /*****************************************************************************/
 
+/** Time difference [ns] to tolerate without setting a new system time offset.
+ */
+#define EC_SYSTEM_TIME_TOLERANCE_NS 100000000
+
+/*****************************************************************************/
+
 void ec_fsm_master_state_start(ec_fsm_master_t *);
 void ec_fsm_master_state_broadcast(ec_fsm_master_t *);
 void ec_fsm_master_state_read_state(ec_fsm_master_t *);
@@ -54,11 +60,14 @@
 void ec_fsm_master_state_clear_addresses(ec_fsm_master_t *);
 void ec_fsm_master_state_dc_measure_delays(ec_fsm_master_t *);
 void ec_fsm_master_state_scan_slave(ec_fsm_master_t *);
+void ec_fsm_master_state_dc_read_offset(ec_fsm_master_t *);
+void ec_fsm_master_state_dc_write_offset(ec_fsm_master_t *);
 void ec_fsm_master_state_write_sii(ec_fsm_master_t *);
 void ec_fsm_master_state_sdo_dictionary(ec_fsm_master_t *);
 void ec_fsm_master_state_sdo_request(ec_fsm_master_t *);
 void ec_fsm_master_state_reg_request(ec_fsm_master_t *);
 
+void ec_fsm_master_enter_write_system_times(ec_fsm_master_t *);
 
 /*****************************************************************************/
 
@@ -290,13 +299,25 @@
     }
 
     if (master->slave_count) {
-        // fetch state from first slave
-        fsm->slave = master->slaves;
-        ec_datagram_fprd(fsm->datagram, fsm->slave->station_address,
-                0x0130, 2);
-        ec_datagram_zero(datagram);
-        fsm->retries = EC_FSM_RETRIES;
-        fsm->state = ec_fsm_master_state_read_state;
+
+        // application applied configurations
+        if (master->config_changed) {
+            master->config_changed = 0;
+
+            EC_MASTER_DBG(master, 1, "Configuration changed.\n");
+
+            fsm->slave = master->slaves; // begin with first slave
+            ec_fsm_master_enter_write_system_times(fsm);
+
+        } else {
+            // fetch state from first slave
+            fsm->slave = master->slaves;
+            ec_datagram_fprd(fsm->datagram, fsm->slave->station_address,
+                    0x0130, 2);
+            ec_datagram_zero(datagram);
+            fsm->retries = EC_FSM_RETRIES;
+            fsm->state = ec_fsm_master_state_read_state;
+        }
     } else {
         ec_fsm_master_restart(fsm);
     }
@@ -787,7 +808,12 @@
     ec_master_eoe_start(master);
 #endif
 
-    ec_fsm_master_restart(fsm);
+    if (master->slave_count) {
+        fsm->slave = master->slaves; // begin with first slave
+        ec_fsm_master_enter_write_system_times(fsm);
+    } else {
+        ec_fsm_master_restart(fsm);
+    }
 }
 
 /*****************************************************************************/
@@ -821,6 +847,208 @@
 
 /*****************************************************************************/
 
+/** Start writing DC system times.
+ */
+void ec_fsm_master_enter_write_system_times(
+        ec_fsm_master_t *fsm /**< Master state machine. */
+        )
+{
+    ec_master_t *master = fsm->master;
+
+    EC_MASTER_DBG(master, 1, "Writing system time offsets...\n");
+
+    if (master->has_app_time) {
+        while (fsm->slave < master->slaves + master->slave_count) {
+            if (!fsm->slave->base_dc_supported
+                    || !fsm->slave->has_dc_system_time) {
+                fsm->slave++;
+                continue;
+            }
+
+            // read DC system time (0x0910, 64 bit)
+            //                         gap (64 bit)
+            //     and time offset (0x0920, 64 bit)
+            ec_datagram_fprd(fsm->datagram, fsm->slave->station_address,
+                    0x0910, 24);
+            fsm->retries = EC_FSM_RETRIES;
+            fsm->state = ec_fsm_master_state_dc_read_offset;
+            return;
+        }
+    } else {
+        EC_MASTER_DBG(master, 1, "No app_time received up to now.\n");
+    }
+
+    ec_master_request_op(master);
+    ec_fsm_master_restart(fsm);
+}
+
+/*****************************************************************************/
+
+/** Configure 32 bit time offset.
+ */
+u64 ec_fsm_master_dc_offset32(
+        ec_fsm_master_t *fsm, /**< Master state machine. */
+        u64 system_time, /**< System time register. */
+        u64 old_offset, /**< Time offset register. */
+        unsigned long jiffies_since_read /**< Jiffies for correction. */
+        )
+{
+    ec_slave_t *slave = fsm->slave;
+    u32 correction, system_time32, old_offset32, new_offset;
+    s32 time_diff;
+
+    system_time32 = (u32) system_time;
+    old_offset32 = (u32) old_offset;
+
+    // correct read system time by elapsed time since read operation
+    correction = jiffies_since_read * 1000 / HZ * 1000000;
+    system_time32 += correction;
+    time_diff = (u32) slave->master->app_time - system_time32;
+
+    EC_SLAVE_DBG(slave, 1, "DC system time offset calculation:"
+            " system_time=%u (corrected with %u),"
+            " app_time=%u, diff=%i\n",
+            system_time32, correction,
+            (u32) slave->master->app_time, time_diff);
+
+    if (EC_ABS(time_diff) > EC_SYSTEM_TIME_TOLERANCE_NS) {
+        new_offset = time_diff + old_offset32;
+        EC_SLAVE_DBG(slave, 1, "Setting time offset to %u (was %u)\n",
+                new_offset, old_offset32);
+        return (u64) new_offset;
+    } else {
+        EC_SLAVE_DBG(slave, 1, "Not touching time offset.\n");
+        return old_offset;
+    }
+}
+
+/*****************************************************************************/
+
+/** Configure 64 bit time offset.
+ */
+u64 ec_fsm_master_dc_offset64(
+        ec_fsm_master_t *fsm, /**< Master state machine. */
+        u64 system_time, /**< System time register. */
+        u64 old_offset, /**< Time offset register. */
+        unsigned long jiffies_since_read /**< Jiffies for correction. */
+        )
+{
+    ec_slave_t *slave = fsm->slave;
+    u64 new_offset, correction;
+    s64 time_diff;
+
+    // correct read system time by elapsed time since read operation
+    correction = (u64) (jiffies_since_read * 1000 / HZ) * 1000000;
+    system_time += correction;
+    time_diff = fsm->slave->master->app_time - system_time;
+
+    EC_SLAVE_DBG(slave, 1, "DC system time offset calculation:"
+            " system_time=%llu (corrected with %llu),"
+            " app_time=%llu, diff=%lli\n",
+            system_time, correction,
+            slave->master->app_time, time_diff);
+
+    if (EC_ABS(time_diff) > EC_SYSTEM_TIME_TOLERANCE_NS) {
+        new_offset = time_diff + old_offset;
+        EC_SLAVE_DBG(slave, 1, "Setting time offset to %llu (was %llu)\n",
+                new_offset, old_offset);
+    } else {
+        new_offset = old_offset;
+        EC_SLAVE_DBG(slave, 1, "Not touching time offset.\n");
+    }
+
+    return new_offset;
+}
+
+/*****************************************************************************/
+
+/** Master state: DC READ OFFSET.
+ */
+void ec_fsm_master_state_dc_read_offset(
+        ec_fsm_master_t *fsm /**< Master state machine. */
+        )
+{
+    ec_datagram_t *datagram = fsm->datagram;
+    ec_slave_t *slave = fsm->slave;
+    u64 system_time, old_offset, new_offset;
+    unsigned long jiffies_since_read;
+
+    if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
+        return;
+
+    if (datagram->state != EC_DATAGRAM_RECEIVED) {
+        EC_SLAVE_ERR(slave, "Failed to receive DC times datagram: ");
+        ec_datagram_print_state(datagram);
+        fsm->slave++;
+        ec_fsm_master_enter_write_system_times(fsm);
+        return;
+    }
+
+    if (datagram->working_counter != 1) {
+        EC_SLAVE_WARN(slave, "Failed to get DC times: ");
+        ec_datagram_print_wc_error(datagram);
+        fsm->slave++;
+        ec_fsm_master_enter_write_system_times(fsm);
+        return;
+    }
+
+    system_time = EC_READ_U64(datagram->data);     // 0x0910
+    old_offset = EC_READ_U64(datagram->data + 16); // 0x0920
+    jiffies_since_read = jiffies - datagram->jiffies_sent;
+
+    if (slave->base_dc_range == EC_DC_32) {
+        new_offset = ec_fsm_master_dc_offset32(fsm,
+                system_time, old_offset, jiffies_since_read);
+    } else {
+        new_offset = ec_fsm_master_dc_offset64(fsm,
+                system_time, old_offset, jiffies_since_read);
+    }
+
+    // set DC system time offset and transmission delay
+    ec_datagram_fpwr(datagram, slave->station_address, 0x0920, 12);
+    EC_WRITE_U64(datagram->data, new_offset);
+    EC_WRITE_U32(datagram->data + 8, slave->transmission_delay);
+    fsm->retries = EC_FSM_RETRIES;
+    fsm->state = ec_fsm_master_state_dc_write_offset;
+}
+
+/*****************************************************************************/
+
+/** Master state: DC WRITE OFFSET.
+ */
+void ec_fsm_master_state_dc_write_offset(
+        ec_fsm_master_t *fsm /**< Master state machine. */
+        )
+{
+    ec_datagram_t *datagram = fsm->datagram;
+    ec_slave_t *slave = fsm->slave;
+
+    if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
+        return;
+
+    if (datagram->state != EC_DATAGRAM_RECEIVED) {
+        EC_SLAVE_ERR(slave,
+                "Failed to receive DC system time offset datagram: ");
+        ec_datagram_print_state(datagram);
+        fsm->slave++;
+        ec_fsm_master_enter_write_system_times(fsm);
+        return;
+    }
+
+    if (datagram->working_counter != 1) {
+        EC_SLAVE_ERR(slave, "Failed to set DC system time offset: ");
+        ec_datagram_print_wc_error(datagram);
+        fsm->slave++;
+        ec_fsm_master_enter_write_system_times(fsm);
+        return;
+    }
+
+    fsm->slave++;
+    ec_fsm_master_enter_write_system_times(fsm);
+}
+
+/*****************************************************************************/
+
 /** Master state: WRITE SII.
  */
 void ec_fsm_master_state_write_sii(
--- a/master/fsm_slave_config.c	Thu May 06 11:41:25 2010 +0200
+++ b/master/fsm_slave_config.c	Thu May 06 11:42:52 2010 +0200
@@ -44,9 +44,20 @@
 
 /*****************************************************************************/
 
-/** Time difference [ns] to tolerate without setting a new system time offset.
- */
-#define EC_SYSTEM_TIME_TOLERANCE_NS 100000000
+/** Maximum clock difference (in ns) before going to SAFEOP.
+ *
+ * Wait for DC time difference to drop under this absolute value before
+ * requesting SAFEOP.
+ */
+#define EC_DC_MAX_SYNC_DIFF_NS 5000
+
+/** Maximum time (in ms) to wait for clock discipline.
+ */
+#define EC_DC_SYNC_WAIT_MS 5000
+
+/** Time offset (in ns), that is added to cyclic start time.
+ */
+#define EC_DC_START_OFFSET 100000000ULL
 
 /*****************************************************************************/
 
@@ -55,8 +66,6 @@
 void ec_fsm_slave_config_state_clear_fmmus(ec_fsm_slave_config_t *);
 void ec_fsm_slave_config_state_clear_sync(ec_fsm_slave_config_t *);
 void ec_fsm_slave_config_state_dc_clear_assign(ec_fsm_slave_config_t *);
-void ec_fsm_slave_config_state_dc_read_offset(ec_fsm_slave_config_t *);
-void ec_fsm_slave_config_state_dc_write_offset(ec_fsm_slave_config_t *);
 void ec_fsm_slave_config_state_mbox_sync(ec_fsm_slave_config_t *);
 void ec_fsm_slave_config_state_boot_preop(ec_fsm_slave_config_t *);
 void ec_fsm_slave_config_state_sdo_conf(ec_fsm_slave_config_t *);
@@ -67,6 +76,7 @@
 void ec_fsm_slave_config_state_pdo_conf(ec_fsm_slave_config_t *);
 void ec_fsm_slave_config_state_fmmu(ec_fsm_slave_config_t *);
 void ec_fsm_slave_config_state_dc_cycle(ec_fsm_slave_config_t *);
+void ec_fsm_slave_config_state_dc_sync_check(ec_fsm_slave_config_t *);
 void ec_fsm_slave_config_state_dc_start(ec_fsm_slave_config_t *);
 void ec_fsm_slave_config_state_dc_assign(ec_fsm_slave_config_t *);
 void ec_fsm_slave_config_state_safeop(ec_fsm_slave_config_t *);
@@ -391,172 +401,6 @@
         ec_datagram_print_wc_error(datagram);
     }
 
-    // read DC system time (0x0910, 64 bit)
-    //                         gap (64 bit)
-    //     and time offset (0x0920, 64 bit)
-    ec_datagram_fprd(fsm->datagram, fsm->slave->station_address, 0x0910, 24);
-    fsm->retries = EC_FSM_RETRIES;
-    fsm->state = ec_fsm_slave_config_state_dc_read_offset;
-}
-
-/*****************************************************************************/
-
-/** Configure 32 bit time offset.
- */
-u64 ec_fsm_slave_config_dc_offset32(
-        ec_fsm_slave_config_t *fsm, /**< slave state machine */
-        u64 system_time, /**< System time register. */
-        u64 old_offset, /**< Time offset register. */
-        unsigned long jiffies_since_read /**< Jiffies for correction. */
-        )
-{
-    ec_slave_t *slave = fsm->slave;
-    u32 correction, system_time32, old_offset32, new_offset;
-    s32 time_diff;
-
-    system_time32 = (u32) system_time;
-    old_offset32 = (u32) old_offset;
-
-    // correct read system time by elapsed time since read operation
-    correction = jiffies_since_read * 1000 / HZ * 1000000;
-    system_time32 += correction;
-    time_diff = (u32) slave->master->app_time - system_time32;
-
-    EC_SLAVE_DBG(slave, 1, "Calculating DC time offset (32 bit):"
-            " system_time=%u (corrected with %u), app_time=%u, diff=%i\n",
-            system_time32, correction,
-            (u32) slave->master->app_time, time_diff);
-
-    if (EC_ABS(time_diff) > EC_SYSTEM_TIME_TOLERANCE_NS) {
-        new_offset = time_diff + old_offset32;
-        EC_SLAVE_DBG(slave, 1, "Setting time offset to %u (was %u)\n",
-                new_offset, old_offset32);
-        return (u64) new_offset;
-    } else {
-        EC_SLAVE_DBG(slave, 1, "Not touching time offset.\n");
-        return old_offset;
-    }
-}
-
-/*****************************************************************************/
-
-/** Configure 64 bit time offset.
- */
-u64 ec_fsm_slave_config_dc_offset64(
-        ec_fsm_slave_config_t *fsm, /**< slave state machine */
-        u64 system_time, /**< System time register. */
-        u64 old_offset, /**< Time offset register. */
-        unsigned long jiffies_since_read /**< Jiffies for correction. */
-        )
-{
-    ec_slave_t *slave = fsm->slave;
-    u64 new_offset, correction;
-    s64 time_diff;
-
-    // correct read system time by elapsed time since read operation
-    correction = (u64) (jiffies_since_read * 1000 / HZ) * 1000000;
-    system_time += correction;
-    time_diff = fsm->slave->master->app_time - system_time;
-
-    EC_SLAVE_DBG(slave, 1, "Calculating DC time offset (64 bit):"
-            " system_time=%llu (corrected with %llu),"
-            " app_time=%llu, diff=%lli\n",
-            system_time, correction,
-            slave->master->app_time, time_diff);
-
-    if (EC_ABS(time_diff) > EC_SYSTEM_TIME_TOLERANCE_NS) {
-        new_offset = time_diff + old_offset;
-        EC_SLAVE_DBG(slave, 1, "Setting time offset to %llu (was %llu)\n",
-                new_offset, old_offset);
-    } else {
-        new_offset = old_offset;
-        EC_SLAVE_DBG(slave, 1, "Not touching time offset.\n");
-    }
-
-    return new_offset;
-}
-
-/*****************************************************************************/
-
-/** Slave configuration state: DC READ OFFSET.
- */
-void ec_fsm_slave_config_state_dc_read_offset(
-        ec_fsm_slave_config_t *fsm /**< slave state machine */
-        )
-{
-    ec_datagram_t *datagram = fsm->datagram;
-    ec_slave_t *slave = fsm->slave;
-    u64 system_time, old_offset, new_offset;
-    unsigned long jiffies_since_read;
-
-    if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
-        return;
-
-    if (datagram->state != EC_DATAGRAM_RECEIVED) {
-        fsm->state = ec_fsm_slave_config_state_error;
-        EC_SLAVE_ERR(slave, "Failed to receive DC times datagram: ");
-        ec_datagram_print_state(datagram);
-        return;
-    }
-
-    if (datagram->working_counter != 1) {
-        slave->error_flag = 1;
-        fsm->state = ec_fsm_slave_config_state_error;
-        EC_SLAVE_ERR(slave, "Failed to get DC times: ");
-        ec_datagram_print_wc_error(datagram);
-        return;
-    }
-
-    system_time = EC_READ_U64(datagram->data);     // 0x0910
-    old_offset = EC_READ_U64(datagram->data + 16); // 0x0920
-    jiffies_since_read = jiffies - datagram->jiffies_sent;
-
-    if (slave->base_dc_range == EC_DC_32) {
-        new_offset = ec_fsm_slave_config_dc_offset32(fsm,
-                system_time, old_offset, jiffies_since_read);
-    } else {
-        new_offset = ec_fsm_slave_config_dc_offset64(fsm,
-                system_time, old_offset, jiffies_since_read);
-    }
-
-    // set DC system time offset and transmission delay
-    ec_datagram_fpwr(datagram, slave->station_address, 0x0920, 12);
-    EC_WRITE_U64(datagram->data, new_offset);
-    EC_WRITE_U32(datagram->data + 8, slave->transmission_delay);
-    fsm->retries = EC_FSM_RETRIES;
-    fsm->state = ec_fsm_slave_config_state_dc_write_offset;
-}
-
-/*****************************************************************************/
-
-/** Slave configuration state: DC WRITE OFFSET.
- */
-void ec_fsm_slave_config_state_dc_write_offset(
-        ec_fsm_slave_config_t *fsm /**< slave state machine */
-        )
-{
-    ec_datagram_t *datagram = fsm->datagram;
-    ec_slave_t *slave = fsm->slave;
-
-    if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
-        return;
-
-    if (datagram->state != EC_DATAGRAM_RECEIVED) {
-        fsm->state = ec_fsm_slave_config_state_error;
-        EC_SLAVE_ERR(slave, "Failed to receive DC system time offset"
-                " datagram: ");
-        ec_datagram_print_state(datagram);
-        return;
-    }
-
-    if (datagram->working_counter != 1) {
-        slave->error_flag = 1;
-        fsm->state = ec_fsm_slave_config_state_error;
-        EC_SLAVE_ERR(slave, "Failed to set DC system time offset: ");
-        ec_datagram_print_wc_error(datagram);
-        return;
-    }
-
     ec_fsm_slave_config_enter_mbox_sync(fsm);
 }
 
@@ -1319,8 +1163,53 @@
 {
     ec_datagram_t *datagram = fsm->datagram;
     ec_slave_t *slave = fsm->slave;
+    ec_slave_config_t *config = slave->config;
+
+    if (!config) { // config removed in the meantime
+        ec_fsm_slave_config_reconfigure(fsm);
+        return;
+    }
+
+    if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
+        return;
+
+    if (datagram->state != EC_DATAGRAM_RECEIVED) {
+        fsm->state = ec_fsm_slave_config_state_error;
+        EC_SLAVE_ERR(slave, "Failed to receive DC cycle times datagram: ");
+        ec_datagram_print_state(datagram);
+        return;
+    }
+
+    if (datagram->working_counter != 1) {
+        slave->error_flag = 1;
+        fsm->state = ec_fsm_slave_config_state_error;
+        EC_SLAVE_ERR(slave, "Failed to set DC cycle times: ");
+        ec_datagram_print_wc_error(datagram);
+        return;
+    }
+
+    EC_SLAVE_DBG(slave, 1, "Checking for synchrony.\n");
+
+    fsm->jiffies_start = jiffies;
+    ec_datagram_fprd(datagram, slave->station_address, 0x092c, 4);
+    fsm->retries = EC_FSM_RETRIES;
+    fsm->state = ec_fsm_slave_config_state_dc_sync_check;
+}
+
+/*****************************************************************************/
+
+/** Slave configuration state: DC SYNC CHECK.
+ */
+void ec_fsm_slave_config_state_dc_sync_check(
+        ec_fsm_slave_config_t *fsm /**< slave state machine */
+        )
+{
+    ec_datagram_t *datagram = fsm->datagram;
+    ec_slave_t *slave = fsm->slave;
     ec_master_t *master = slave->master;
     ec_slave_config_t *config = slave->config;
+    uint32_t abs_sync_diff;
+    unsigned long diff_ms;
     ec_sync_signal_t *sync0 = &config->dc_sync[0];
     u64 start_time;
 
@@ -1334,7 +1223,7 @@
 
     if (datagram->state != EC_DATAGRAM_RECEIVED) {
         fsm->state = ec_fsm_slave_config_state_error;
-        EC_SLAVE_ERR(slave, "Failed to receive DC cycle times datagram: ");
+        EC_SLAVE_ERR(slave, "Failed to receive DC sync check datagram: ");
         ec_datagram_print_state(datagram);
         return;
     }
@@ -1342,18 +1231,40 @@
     if (datagram->working_counter != 1) {
         slave->error_flag = 1;
         fsm->state = ec_fsm_slave_config_state_error;
-        EC_SLAVE_ERR(slave, "Failed to set DC cycle times: ");
+        EC_SLAVE_ERR(slave, "Failed to check DC synchrony: ");
         ec_datagram_print_wc_error(datagram);
         return;
     }
 
+    abs_sync_diff = EC_READ_U32(datagram->data) & 0x7fffffff;
+    diff_ms = (datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
+
+    if (abs_sync_diff > EC_DC_MAX_SYNC_DIFF_NS) {
+
+        if (diff_ms >= EC_DC_SYNC_WAIT_MS) {
+            EC_SLAVE_WARN(slave, "Slave did not sync after %u ms.\n",
+                    (u32) diff_ms);
+        } else {
+            EC_SLAVE_DBG(slave, 1, "Sync after %4u ms: %10u ns\n",
+                    (u32) diff_ms, abs_sync_diff);
+
+            // check synchrony again
+            ec_datagram_fprd(datagram, slave->station_address, 0x092c, 4);
+            fsm->retries = EC_FSM_RETRIES;
+            return;
+        }
+    } else {
+        EC_SLAVE_DBG(slave, 1, "%u ns difference after %u ms.\n",
+                abs_sync_diff, (u32) diff_ms);
+    }
+
     // set DC start time
-    start_time = master->app_time + 100000000ULL; // now + X ns
+    start_time = master->app_time + EC_DC_START_OFFSET; // now + X ns
     // FIXME use slave's local system time here?
 
     if (sync0->cycle_time) {
         // find correct phase
-        if (master->has_start_time) {
+        if (master->has_app_time) {
             u64 diff, start;
             u32 remainder;
 
@@ -1363,20 +1274,13 @@
             start = start_time +
                 sync0->cycle_time - remainder + sync0->shift_time;
 
-            if (master->debug_level) {
-                EC_SLAVE_DBG(slave, 1, "app_start_time=%llu\n",
-                        master->app_start_time);
-                EC_SLAVE_DBG(slave, 1, "    start_time=%llu\n",
-                        start_time);
-                EC_SLAVE_DBG(slave, 1, "    cycle_time=%u\n",
-                        sync0->cycle_time);
-                EC_SLAVE_DBG(slave, 1, "    shift_time=%u\n",
-                        sync0->shift_time);
-                EC_SLAVE_DBG(slave, 1, "     remainder=%u\n",
-                        remainder);
-                EC_SLAVE_DBG(slave, 1, "         start=%llu\n",
-                        start);
-            }
+            EC_SLAVE_DBG(slave, 1, "app_start_time=%llu\n",
+                    master->app_start_time);
+            EC_SLAVE_DBG(slave, 1, "    start_time=%llu\n", start_time);
+            EC_SLAVE_DBG(slave, 1, "    cycle_time=%u\n", sync0->cycle_time);
+            EC_SLAVE_DBG(slave, 1, "    shift_time=%u\n", sync0->shift_time);
+            EC_SLAVE_DBG(slave, 1, "     remainder=%u\n", remainder);
+            EC_SLAVE_DBG(slave, 1, "         start=%llu\n", start);
             start_time = start;
         } else {
             EC_SLAVE_WARN(slave, "No application time supplied."
--- a/master/master.c	Thu May 06 11:41:25 2010 +0200
+++ b/master/master.c	Thu May 06 11:42:52 2010 +0200
@@ -139,6 +139,7 @@
 
     master->phase = EC_ORPHANED;
     master->active = 0;
+    master->config_changed = 0;
     master->injection_seq_fsm = 0;
     master->injection_seq_rt = 0;
 
@@ -149,7 +150,7 @@
 
     master->app_time = 0ULL;
     master->app_start_time = 0ULL;
-    master->has_start_time = 0;
+    master->has_app_time = 0;
 
     master->scan_busy = 0;
     master->allow_scan = 1;
@@ -1824,6 +1825,37 @@
     ec_master_calc_transmission_delays(master);
 }
 
+/*****************************************************************************/
+
+/** Request OP state for configured slaves.
+ */
+void ec_master_request_op(
+        ec_master_t *master /**< EtherCAT master. */
+        )
+{
+    unsigned int i;
+    ec_slave_t *slave;
+
+    if (!master->active)
+        return;
+
+    EC_MASTER_DBG(master, 1, "Requesting OP...\n");
+
+    // request OP for all configured slaves
+    for (i = 0; i < master->slave_count; i++) {
+        slave = master->slaves + i;
+        if (slave->config) {
+            ec_slave_request_state(slave, EC_SLAVE_STATE_OP);
+        }
+    }
+
+    // always set DC reference clock to OP
+    if (master->dc_ref_clock) {
+        ec_slave_request_state(master->dc_ref_clock,
+                EC_SLAVE_STATE_OP);
+    }
+}
+
 /******************************************************************************
  *  Application interface
  *****************************************************************************/
@@ -1906,11 +1938,6 @@
         domain_offset += domain->data_size;
     }
     
-    // always set DC reference clock to OP
-    if (master->dc_ref_clock) {
-        ec_slave_request_state(master->dc_ref_clock, EC_SLAVE_STATE_OP);
-    }
-
     up(&master->master_sem);
 
     // restart EoE process and master thread with new locking
@@ -1945,6 +1972,10 @@
     master->allow_config = 1; // request the current configuration
     master->allow_scan = 1; // allow re-scanning on topology change
     master->active = 1;
+
+    // notify state machine, that the configuration shall now be applied
+    master->config_changed = 1;
+
     return 0;
 }
 
@@ -2004,7 +2035,7 @@
 
     master->app_time = 0ULL;
     master->app_start_time = 0ULL;
-    master->has_start_time = 0;
+    master->has_app_time = 0;
 
 #ifdef EC_EOE
     if (eoe_was_running) {
@@ -2258,9 +2289,9 @@
 {
     master->app_time = app_time;
 
-    if (unlikely(!master->has_start_time)) {
+    if (unlikely(!master->has_app_time)) {
         master->app_start_time = app_time;
-        master->has_start_time = 1;
+        master->has_app_time = 1;
     }
 }
 
--- a/master/master.h	Thu May 06 11:41:25 2010 +0200
+++ b/master/master.h	Thu May 06 11:42:52 2010 +0200
@@ -164,6 +164,7 @@
     ec_datagram_t fsm_datagram; /**< Datagram used for state machines. */
     ec_master_phase_t phase; /**< Master phase. */
     unsigned int active; /**< Master has been activated. */
+    unsigned int config_changed; /**< The configuration changed. */
     unsigned int injection_seq_fsm; /**< Datagram injection sequence number
                                       for the FSM side. */
     unsigned int injection_seq_rt; /**< Datagram injection sequence number
@@ -177,7 +178,7 @@
     
     u64 app_time; /**< Time of the last ecrt_master_sync() call. */
     u64 app_start_time; /**< Application start time. */
-    u8 has_start_time; /**< Start time already taken. */
+    u8 has_app_time; /**< Application time is valid. */
     ec_datagram_t ref_sync_datagram; /**< Datagram used for synchronizing the
                                        reference clock to the master clock. */
     ec_datagram_t sync_datagram; /**< Datagram used for DC drift
@@ -306,6 +307,7 @@
         uint16_t, uint32_t, uint32_t);
 
 void ec_master_calc_dc(ec_master_t *);
+void ec_master_request_op(ec_master_t *);
 
 void ec_master_internal_send_cb(void *);
 void ec_master_internal_receive_cb(void *);