Improved master state machine.
authorFlorian Pose <fp@igh-essen.com>
Fri, 25 Apr 2008 14:07:38 +0000
changeset 907 570ae1c64465
parent 906 f95e3e33c0cf
child 908 386b908033be
Improved master state machine.
TODO
documentation/graphs/fsm_master.dot
master/fsm_master.c
--- a/TODO	Fri Apr 25 12:45:44 2008 +0000
+++ b/TODO	Fri Apr 25 14:07:38 2008 +0000
@@ -20,10 +20,11 @@
   portability.
 * Remove ecdb.h and let lsec output PDO information 'cut-and-pastable' for
   applications.
+* Scanning of Sdo dictionary / writing EEPROM in OPERATION state.
+* Remove the end state of the master state machine.
 * SDO write access in sysfs.
 * Update documentation.
 * Supply new ec_master_state_t.
-* Scanning of Sdo dictionary / writing EEPROM in OPERATION state.
 * Adapt remaining examples.
 * READMEs for examples.
 * Separate Pdo and Pdo entry classes.
@@ -31,12 +32,11 @@
 * Wait for bus scanning, even when link is not up at ecrt_request_master().
 * Implement ecrt_slave_config_state().
 * Add something like lsec -n to show numeric vendor IDs.
-* Remove the end state of the master state machine.
-* Check the position of the acknowledge state.
 * Remove the xmldev files.
 * Separate CoE debugging.
 * Make ecrt_master_slave_config() return no error when slave is not present
   or invalid.
+* Evaluate EEPROM contents after writing.
 
 Future issues:
 
@@ -45,7 +45,6 @@
   kernel threads to user space daemon with a TCP interface replacing the
   cdev).
 * Mailbox gateway.
-* Slave-to-slave communication.
 * Redundancy with 2 network adapters.
 * Interface/buffers for asynchronous domain IO.
 
@@ -54,14 +53,9 @@
 * Evaluate SII Size field (0x003E) to determine maximum SII memory size.
 * Unite fsm_pdo_mapping, fsm_pdo_config and fsm_coe_map.
 * Clear sync managers in INIT.
-* Simplify FSMs with <state>_enter() functions.
 * Read out CRC counters.
 * Optimize alignment of process data.
-* Evaluate EEPROM contents after writing.
 * Configure slave ports to automatically open on link detection.
-* Interrupt master state machines state scan for other jobs.
-* Master state machine, slave configuration: Do not check every slave on
-  a cycle.
 * Only execute one EoE handler per EoE cycle.
 
 Less important issues:
--- a/documentation/graphs/fsm_master.dot	Fri Apr 25 12:45:44 2008 +0000
+++ b/documentation/graphs/fsm_master.dot	Fri Apr 25 14:07:38 2008 +0000
@@ -6,62 +6,64 @@
     center=1
 	ratio=fill
 
-    action_process_sii [shape=point,label=""]
-    action_process_sdo [shape=point,label=""]
-    action_configure [shape=point,label=""]
-    action_next_slave_state [shape=point,label=""]
-    action_process_states [shape=point,label=""]
-
+    start [fontname="Helvetica"]
     start -> broadcast [weight=10]
 
-    //broadcast -> error
+    broadcast [fontname="Helvetica"]
     broadcast -> end
     broadcast -> clear_addresses
-    broadcast -> read_states [weight=10]
+    broadcast -> read_state [weight=10]
 
+    action_process_sii [shape=point,label=""]
     action_process_sii -> write_sii
 
+    action_process_sdo [shape=point,label=""]
     action_process_sdo -> sdo_request
 
-    action_configure -> configure_slave
+    action_idle [shape=point,label=""]
+    action_idle -> action_process_sdo
+    action_idle -> sdo_dictionary
+    action_idle -> action_process_sii
+    action_idle -> end
 
-    action_process_states -> action_configure
-    action_process_states -> action_process_sdo
-    action_process_states -> sdo_dictionary
-    action_process_states -> action_process_sii
-    action_process_states -> end
+    action_next_slave_state [shape=point,label=""]
+    action_next_slave_state -> read_state
+    action_next_slave_state -> action_idle [weight=10]
+    
+    action_configure [shape=point,label=""]
+    action_configure -> configure_slave [weight=10]
+    action_configure -> action_next_slave_state
 
-    action_next_slave_state -> read_states
-    action_next_slave_state -> action_process_states
+    action_acknowledge [shape=point,label=""]
+    action_acknowledge -> acknowledge [weight=10]
+    action_acknowledge -> action_configure
+    action_acknowledge -> action_next_slave_state
 
-    //read_states -> error
-    read_states -> action_next_slave_state
-    read_states -> acknowledge
+    read_state [fontname="Helvetica"]
+    read_state -> action_acknowledge [weight=10]
 
-    //acknowledge -> error
-    acknowledge -> action_next_slave_state
+    acknowledge [fontname="Helvetica"]
+    acknowledge -> action_configure [weight=10]
 
-    //clear_addresses -> error
-    clear_addresses -> scan_slaves
+    clear_addresses [fontname="Helvetica"]
+    clear_addresses -> scan_slave [weight=10]
 
-    scan_slaves -> scan_slaves
-    scan_slaves -> end
+    scan_slave [fontname="Helvetica"]
+    scan_slave -> end
 
-    configure_slave -> action_configure
-    configure_slave -> end
+    configure_slave [fontname="Helvetica"]
+    configure_slave -> action_next_slave_state [weight=10]
 
-    //write_sii -> error
+    write_sii [fontname="Helvetica"]
     write_sii -> action_process_sii
     write_sii -> end
 
-    //sdo_dictionary -> error
+    sdo_dictionary [fontname="Helvetica"]
     sdo_dictionary -> end
 
-    //sdo_request -> error
+    sdo_request [fontname="Helvetica"]
     sdo_request -> action_process_sdo
     sdo_request -> end
 
-    //error -> start
-
-    //end -> start
+    end [fontname="Helvetica"]
 }
--- a/master/fsm_master.c	Fri Apr 25 12:45:44 2008 +0000
+++ b/master/fsm_master.c	Fri Apr 25 14:07:38 2008 +0000
@@ -31,10 +31,9 @@
  *
  *****************************************************************************/
 
-/**
-   \file
-   EtherCAT finite state machines.
-*/
+/** \file
+ * EtherCAT master state machine.
+ */
 
 /*****************************************************************************/
 
@@ -52,11 +51,11 @@
 
 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_states(ec_fsm_master_t *);
+void ec_fsm_master_state_read_state(ec_fsm_master_t *);
 void ec_fsm_master_state_acknowledge(ec_fsm_master_t *);
 void ec_fsm_master_state_configure_slave(ec_fsm_master_t *);
 void ec_fsm_master_state_clear_addresses(ec_fsm_master_t *);
-void ec_fsm_master_state_scan_slaves(ec_fsm_master_t *);
+void ec_fsm_master_state_scan_slave(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 *);
@@ -65,13 +64,12 @@
 
 /*****************************************************************************/
 
-/**
-   Constructor.
-*/
-
-void ec_fsm_master_init(ec_fsm_master_t *fsm, /**< master state machine */
-        ec_master_t *master, /**< EtherCAT master */
-        ec_datagram_t *datagram /**< datagram object to use */
+/** Constructor.
+ */
+void ec_fsm_master_init(
+        ec_fsm_master_t *fsm, /**< Master state machine. */
+        ec_master_t *master, /**< EtherCAT master. */
+        ec_datagram_t *datagram /**< Datagram object to use. */
         )
 {
     fsm->master = master;
@@ -94,11 +92,11 @@
 
 /*****************************************************************************/
 
-/**
-   Destructor.
-*/
-
-void ec_fsm_master_clear(ec_fsm_master_t *fsm /**< master state machine */)
+/** Destructor.
+ */
+void ec_fsm_master_clear(
+        ec_fsm_master_t *fsm /**< Master state machine. */
+        )
 {
     // clear sub-state machines
     ec_fsm_slave_config_clear(&fsm->fsm_slave_config);
@@ -111,14 +109,16 @@
 
 /*****************************************************************************/
 
-/**
-   Executes the current state of the state machine.
-   If the state machine's datagram is not sent or received yet, the execution
-   of the state machine is delayed to the next cycle.
-   \return false, if state machine has terminated
-*/
-
-int ec_fsm_master_exec(ec_fsm_master_t *fsm /**< master state machine */)
+/** Executes the current state of the state machine.
+ *
+ * If the state machine's datagram is not sent or received yet, the execution
+ * of the state machine is delayed to the next cycle.
+ *
+ * \return false, if state machine has terminated
+ */
+int ec_fsm_master_exec(
+        ec_fsm_master_t *fsm /**< Master state machine. */
+        )
 {
     if (fsm->datagram->state == EC_DATAGRAM_SENT
         || fsm->datagram->state == EC_DATAGRAM_QUEUED) {
@@ -135,9 +135,8 @@
 /**
  * \return false, if state machine has terminated
  */
-
 int ec_fsm_master_running(
-        const ec_fsm_master_t *fsm /**< master state machine */
+        const ec_fsm_master_t *fsm /**< Master state machine. */
         )
 {
     return fsm->state != ec_fsm_master_state_end
@@ -149,24 +148,24 @@
 /**
  * \return true, if the state machine is in an idle phase
  */
-
 int ec_fsm_master_idle(
-        const ec_fsm_master_t *fsm /**< master state machine */
+        const ec_fsm_master_t *fsm /**< Master state machine. */
         )
 {
     return fsm->idle;
 }
 
 /******************************************************************************
- *  master state machine
+ * Master state machine
  *****************************************************************************/
 
-/**
-   Master state: START.
-   Starts with getting slave count and slave states.
-*/
-
-void ec_fsm_master_state_start(ec_fsm_master_t *fsm)
+/** Master state: START.
+ *
+ * Starts with getting slave count and slave states.
+ */
+void ec_fsm_master_state_start(
+        ec_fsm_master_t *fsm /**< Master state machine. */
+        )
 {
     fsm->idle = 1;
     ec_datagram_brd(fsm->datagram, 0x0130, 2);
@@ -175,12 +174,13 @@
 
 /*****************************************************************************/
 
-/**
-   Master state: BROADCAST.
-   Processes the broadcast read slave count and slaves states.
-*/
-
-void ec_fsm_master_state_broadcast(ec_fsm_master_t *fsm /**< master state machine */)
+/** Master state: BROADCAST.
+ *
+ * Processes the broadcast read slave count and slaves states.
+ */
+void ec_fsm_master_state_broadcast(
+        ec_fsm_master_t *fsm /**< Master state machine. */
+        )
 {
     ec_datagram_t *datagram = fsm->datagram;
     unsigned int i;
@@ -276,23 +276,23 @@
     if (list_empty(&master->slaves)) {
         fsm->state = ec_fsm_master_state_end;
     } else {
-        // fetch state from each slave
+        // fetch state from first slave
         fsm->slave = list_entry(master->slaves.next, ec_slave_t, list);
-        ec_datagram_fprd(fsm->datagram, fsm->slave->station_address, 0x0130, 2);
+        ec_datagram_fprd(fsm->datagram, fsm->slave->station_address,
+                0x0130, 2);
         fsm->retries = EC_FSM_RETRIES;
-        fsm->state = ec_fsm_master_state_read_states;
-    }
-}
-
-/*****************************************************************************/
-
-/**
- * Check for pending SII write requests and process one.
+        fsm->state = ec_fsm_master_state_read_state;
+    }
+}
+
+/*****************************************************************************/
+
+/** Check for pending SII write requests and process one.
+ * 
  * \return non-zero, if an SII write request is processed.
  */
-
 int ec_fsm_master_action_process_sii(
-        ec_fsm_master_t *fsm /**< master state machine */
+        ec_fsm_master_t *fsm /**< Master state machine. */
         )
 {
     ec_master_t *master = fsm->master;
@@ -330,13 +330,12 @@
 
 /*****************************************************************************/
 
-/**
- * Check for pending Sdo requests and process one.
+/** Check for pending Sdo requests and process one.
+ * 
  * \return non-zero, if an Sdo request is processed.
  */
-
 int ec_fsm_master_action_process_sdo(
-        ec_fsm_master_t *fsm /**< master state machine */
+        ec_fsm_master_t *fsm /**< Master state machine. */
         )
 {
     ec_master_t *master = fsm->master;
@@ -425,78 +424,16 @@
 
 /*****************************************************************************/
 
-/**
- * Check for slaves that are not configured and configure them.
- */
-
-int ec_fsm_master_action_configure(
-        ec_fsm_master_t *fsm /**< master state machine */
-        )
-{
+/** Master action: IDLE.
+ *
+ * Does secondary work.
+ */
+void ec_fsm_master_action_idle(
+        ec_fsm_master_t *fsm /**< Master state machine. */
+        )
+{
+    ec_master_t *master = fsm->master;
     ec_slave_t *slave;
-    ec_master_t *master = fsm->master;
-    char old_state[EC_STATE_STRING_SIZE], new_state[EC_STATE_STRING_SIZE];
-
-    // check if any slaves are not in the state, they're supposed to be
-    // FIXME do not check all slaves in every cycle...
-    list_for_each_entry(slave, &master->slaves, list) {
-        if (slave->error_flag
-                || slave->requested_state == EC_SLAVE_STATE_UNKNOWN
-                || (slave->current_state == slave->requested_state
-                    && slave->self_configured)) continue;
-
-        if (master->debug_level) {
-            ec_state_string(slave->current_state, old_state);
-            if (slave->current_state != slave->requested_state) {
-                ec_state_string(slave->requested_state, new_state);
-                EC_DBG("Changing state of slave %i (%s -> %s).\n",
-                        slave->ring_position, old_state, new_state);
-            }
-            else if (!slave->self_configured) {
-                EC_DBG("Reconfiguring slave %i (%s).\n",
-                        slave->ring_position, old_state);
-            }
-        }
-
-        fsm->idle = 0;
-        fsm->slave = slave;
-        fsm->state = ec_fsm_master_state_configure_slave;
-        ec_fsm_slave_config_start(&fsm->fsm_slave_config, slave);
-        ec_fsm_slave_config_exec(&fsm->fsm_slave_config); // execute immediately
-        return 1;
-    }
-
-    master->config_busy = 0;
-    wake_up_interruptible(&master->config_queue);
-    return 0;
-}
-
-/*****************************************************************************/
-
-/**
-   Master action: PROC_STATES.
-   Processes the slave states.
-*/
-
-void ec_fsm_master_action_process_states(ec_fsm_master_t *fsm
-                                         /**< master state machine */
-                                         )
-{
-    ec_master_t *master = fsm->master;
-    ec_slave_t *slave;
-
-    // Start slave configuration, if it is allowed.
-    down(&master->config_sem);
-    if (!master->allow_config) {
-        up(&master->config_sem);
-    } else {
-        master->config_busy = 1;
-        up(&master->config_sem);
-
-        // check for pending slave configurations
-        if (ec_fsm_master_action_configure(fsm))
-            return;
-    }
 
     // Check for pending Sdo requests
     if (ec_fsm_master_action_process_sdo(fsm))
@@ -538,40 +475,118 @@
 
 /*****************************************************************************/
 
-/**
-   Master action: Get state of next slave.
-*/
-
-void ec_fsm_master_action_next_slave_state(ec_fsm_master_t *fsm
-                                           /**< master state machine */)
+/** Master action: Get state of next slave.
+ */
+void ec_fsm_master_action_next_slave_state(
+        ec_fsm_master_t *fsm /**< Master state machine. */
+        )
 {
     ec_master_t *master = fsm->master;
     ec_slave_t *slave = fsm->slave;
 
     // is there another slave to query?
     if (slave->list.next != &master->slaves) {
-        // process next slave
+        // fetch state from next slave
         fsm->idle = 1;
         fsm->slave = list_entry(slave->list.next, ec_slave_t, list);
         ec_datagram_fprd(fsm->datagram, fsm->slave->station_address,
                          0x0130, 2);
         fsm->retries = EC_FSM_RETRIES;
-        fsm->state = ec_fsm_master_state_read_states;
-        return;
-    }
-
-    // all slave states read
-    ec_fsm_master_action_process_states(fsm);
-}
-
-/*****************************************************************************/
-
-/**
-   Master state: READ STATES.
-   Fetches the AL- and online state of a slave.
-*/
-
-void ec_fsm_master_state_read_states(ec_fsm_master_t *fsm /**< master state machine */)
+        fsm->state = ec_fsm_master_state_read_state;
+        return;
+    }
+
+    // all slaves processed
+    ec_fsm_master_action_idle(fsm);
+}
+
+/*****************************************************************************/
+
+/** Master action: Configure.
+ */
+void ec_fsm_master_action_configure(
+        ec_fsm_master_t *fsm /**< Master state machine. */
+        )
+{
+    ec_master_t *master = fsm->master;
+    ec_slave_t *slave = fsm->slave;
+
+    // Does the slave have to be configured?
+    if (!slave->error_flag
+            && (slave->current_state != slave->requested_state
+                || !slave->self_configured)) {
+        // Start slave configuration, if it is allowed.
+        down(&master->config_sem);
+        if (!master->allow_config) {
+            up(&master->config_sem);
+        } else {
+            master->config_busy = 1;
+            up(&master->config_sem);
+
+            if (master->debug_level) {
+                char old_state[EC_STATE_STRING_SIZE];
+                ec_state_string(slave->current_state, old_state);
+                if (slave->current_state != slave->requested_state) {
+                    char new_state[EC_STATE_STRING_SIZE];
+                    ec_state_string(slave->requested_state, new_state);
+                    EC_DBG("Changing state of slave %u (%s -> %s).\n",
+                            slave->ring_position, old_state, new_state);
+                } else if (!slave->self_configured) {
+                    EC_DBG("Reconfiguring slave %u (%s).\n",
+                            slave->ring_position, old_state);
+                }
+            }
+
+            fsm->idle = 0;
+            fsm->state = ec_fsm_master_state_configure_slave;
+            ec_fsm_slave_config_start(&fsm->fsm_slave_config, slave);
+            fsm->state(fsm); // execute immediately
+            return;
+        }
+    }
+
+    // slave has error flag set; process next one
+    ec_fsm_master_action_next_slave_state(fsm);
+}
+
+/*****************************************************************************/
+
+/** Master action: Acknowledge.
+ */
+void ec_fsm_master_action_acknowledge(
+        ec_fsm_master_t *fsm /**< Master state machine. */
+        )
+{
+    ec_slave_t *slave = fsm->slave;
+
+    if (!slave->error_flag) {
+        // Check, if new slave state has to be acknowledged
+        if (slave->current_state & EC_SLAVE_STATE_ACK_ERR) {
+            fsm->idle = 0;
+            fsm->state = ec_fsm_master_state_acknowledge;
+            ec_fsm_change_ack(&fsm->fsm_change, slave);
+            fsm->state(fsm); // execute immediately
+            return;
+        }
+
+        // No acknowlegde necessary; check for configuration
+        ec_fsm_master_action_configure(fsm);
+        return;
+    }
+
+    // slave has error flag set; process next one
+    ec_fsm_master_action_next_slave_state(fsm);
+}
+
+/*****************************************************************************/
+
+/** Master state: READ STATE.
+ *
+ * Fetches the AL state of a slave.
+ */
+void ec_fsm_master_state_read_state(
+        ec_fsm_master_t *fsm /**< Master state machine. */
+        )
 {
     ec_slave_t *slave = fsm->slave;
     ec_datagram_t *datagram = fsm->datagram;
@@ -580,7 +595,7 @@
         return;
 
     if (datagram->state != EC_DATAGRAM_RECEIVED) {
-        EC_ERR("Failed to receive AL state datagram for slave %i"
+        EC_ERR("Failed to receive AL state datagram for slave %u"
                 " (datagram state %i)\n",
                 slave->ring_position, datagram->state);
         fsm->state = ec_fsm_master_state_error;
@@ -600,52 +615,39 @@
         return;
     }
 
-    // a single slave responded
-    ec_slave_set_state(slave, EC_READ_U8(datagram->data)); // set app state first
-
-    // check, if new slave state has to be acknowledged
-    if (slave->current_state & EC_SLAVE_STATE_ACK_ERR && !slave->error_flag) {
-        fsm->idle = 0;
-        fsm->state = ec_fsm_master_state_acknowledge;
-        ec_fsm_change_ack(&fsm->fsm_change, slave);
-        ec_fsm_change_exec(&fsm->fsm_change);
-        return;
-    }
-
-    ec_fsm_master_action_next_slave_state(fsm);
-}
-
-/*****************************************************************************/
-
-/**
-   Master state: ACKNOWLEDGE
-*/
-
-void ec_fsm_master_state_acknowledge(ec_fsm_master_t *fsm /**< master state machine */)
+    // A single slave responded
+    ec_slave_set_state(slave, EC_READ_U8(datagram->data));
+    ec_fsm_master_action_acknowledge(fsm);
+}
+
+/*****************************************************************************/
+
+/** Master state: ACKNOWLEDGE.
+ */
+void ec_fsm_master_state_acknowledge(
+        ec_fsm_master_t *fsm /**< Master state machine. */
+        )
 {
     ec_slave_t *slave = fsm->slave;
 
-    if (ec_fsm_change_exec(&fsm->fsm_change)) return;
+    if (ec_fsm_change_exec(&fsm->fsm_change))
+        return;
 
     if (!ec_fsm_change_success(&fsm->fsm_change)) {
         fsm->slave->error_flag = 1;
-        EC_ERR("Failed to acknowledge state change on slave %i.\n",
+        EC_ERR("Failed to acknowledge state change on slave %u.\n",
                slave->ring_position);
-        fsm->state = ec_fsm_master_state_error;
-        return;
-    }
-
-    ec_fsm_master_action_next_slave_state(fsm);
-}
-
-/*****************************************************************************/
-
-/**
- * Master state: CLEAR ADDRESSES.
- */
-
+    }
+
+    ec_fsm_master_action_configure(fsm);
+}
+
+/*****************************************************************************/
+
+/** Master state: CLEAR ADDRESSES.
+ */
 void ec_fsm_master_state_clear_addresses(
-        ec_fsm_master_t *fsm /**< master state machine */
+        ec_fsm_master_t *fsm /**< Master state machine. */
         )
 {
     ec_master_t *master = fsm->master;
@@ -672,26 +674,25 @@
 
     // begin scanning of slaves
     fsm->slave = list_entry(master->slaves.next, ec_slave_t, list);
-    fsm->state = ec_fsm_master_state_scan_slaves;
+    fsm->state = ec_fsm_master_state_scan_slave;
     ec_fsm_slave_scan_start(&fsm->fsm_slave_scan, fsm->slave);
     ec_fsm_slave_scan_exec(&fsm->fsm_slave_scan); // execute immediately
 }
 
 /*****************************************************************************/
 
-/**
- * Master state: SCAN SLAVES.
+/** Master state: SCAN SLAVE.
+ *
  * Executes the sub-statemachine for the scanning of a slave.
  */
-
-void ec_fsm_master_state_scan_slaves(
-        ec_fsm_master_t *fsm /**< master state machine */
+void ec_fsm_master_state_scan_slave(
+        ec_fsm_master_t *fsm /**< Master state machine. */
         )
 {
     ec_master_t *master = fsm->master;
     ec_slave_t *slave = fsm->slave;
 
-    if (ec_fsm_slave_scan_exec(&fsm->fsm_slave_scan)) // execute slave state machine
+    if (ec_fsm_slave_scan_exec(&fsm->fsm_slave_scan))
         return;
 
 #ifdef EC_EOE
@@ -738,37 +739,38 @@
 
 /*****************************************************************************/
 
-/**
-   Master state: CONFIGURE SLAVES.
-   Starts configuring a slave.
-*/
-
-void ec_fsm_master_state_configure_slave(ec_fsm_master_t *fsm
-                                   /**< master state machine */
-                                   )
-{
-    if (ec_fsm_slave_config_exec(&fsm->fsm_slave_config)) // execute slave's state machine
-        return;
+/** Master state: CONFIGURE SLAVE.
+ *
+ * Starts configuring a slave.
+ */
+void ec_fsm_master_state_configure_slave(
+        ec_fsm_master_t *fsm /**< Master state machine. */
+        )
+{
+    ec_master_t *master = fsm->master;
+
+    if (ec_fsm_slave_config_exec(&fsm->fsm_slave_config))
+        return;
+
+    // configuration finished
+    master->config_busy = 0;
+    wake_up_interruptible(&master->config_queue);
 
     if (!ec_fsm_slave_config_success(&fsm->fsm_slave_config)) {
         // TODO: mark slave_config as failed.
     }
 
-    // configure next slave, if necessary
-    if (ec_fsm_master_action_configure(fsm))
-        return;
-
-    fsm->state = ec_fsm_master_state_end;
-}
-
-/*****************************************************************************/
-
-/**
-   Master state: WRITE SII.
-*/
-
+    fsm->idle = 1;
+    ec_fsm_master_action_next_slave_state(fsm);
+}
+
+/*****************************************************************************/
+
+/** Master state: WRITE SII.
+ */
 void ec_fsm_master_state_write_sii(
-        ec_fsm_master_t *fsm /**< master state machine */)
+        ec_fsm_master_t *fsm /**< Master state machine. */
+        )
 {
     ec_master_t *master = fsm->master;
     ec_sii_write_request_t *request = fsm->sii_request;
@@ -814,12 +816,10 @@
 
 /*****************************************************************************/
 
-/**
-   Master state: SdoDICT.
-*/
-
+/** Master state: SDO DICTIONARY.
+ */
 void ec_fsm_master_state_sdo_dictionary(
-        ec_fsm_master_t *fsm /**< master state machine */
+        ec_fsm_master_t *fsm /**< Master state machine. */
         )
 {
     ec_slave_t *slave = fsm->slave;
@@ -846,11 +846,11 @@
 
 /*****************************************************************************/
 
-/**
-   Master state: SDO REQUEST.
-*/
-
-void ec_fsm_master_state_sdo_request(ec_fsm_master_t *fsm /**< master state machine */)
+/** Master state: SDO REQUEST.
+ */
+void ec_fsm_master_state_sdo_request(
+        ec_fsm_master_t *fsm /**< Master state machine. */
+        )
 {
     ec_master_t *master = fsm->master;
     ec_sdo_request_t *request = fsm->sdo_request;
@@ -883,12 +883,10 @@
 
 /*****************************************************************************/
 
-/**
-   State: ERROR.
-*/
-
+/** State: ERROR.
+ */
 void ec_fsm_master_state_error(
-        ec_fsm_master_t *fsm /**< master state machine */
+        ec_fsm_master_t *fsm /**< Master state machine. */
         )
 {
     fsm->state = ec_fsm_master_state_start;
@@ -896,14 +894,13 @@
 
 /*****************************************************************************/
 
-/**
-   State: END.
-*/
-
-void ec_fsm_master_state_end(ec_fsm_master_t *fsm /**< master state machine */)
+/** State: END.
+ */
+void ec_fsm_master_state_end(
+        ec_fsm_master_t *fsm /**< Master state machine. */
+        )
 {
     fsm->state = ec_fsm_master_state_start;
 }
 
 /*****************************************************************************/
-