master/fsm.c
branchstable-1.0
changeset 1624 9dc190591c0f
parent 1623 05622513f627
--- a/master/fsm.c	Mon Jun 26 16:07:07 2006 +0000
+++ b/master/fsm.c	Wed Aug 02 12:25:25 2006 +0000
@@ -46,32 +46,30 @@
 
 void ec_fsm_master_start(ec_fsm_t *);
 void ec_fsm_master_broadcast(ec_fsm_t *);
-void ec_fsm_master_proc_states(ec_fsm_t *);
-void ec_fsm_master_scan(ec_fsm_t *);
-void ec_fsm_master_states(ec_fsm_t *);
+void ec_fsm_master_read_states(ec_fsm_t *);
 void ec_fsm_master_validate_vendor(ec_fsm_t *);
 void ec_fsm_master_validate_product(ec_fsm_t *);
-void ec_fsm_master_reconfigure(ec_fsm_t *);
-void ec_fsm_master_address(ec_fsm_t *);
-void ec_fsm_master_conf(ec_fsm_t *);
-void ec_fsm_master_eeprom(ec_fsm_t *);
-
-void ec_fsm_slave_start_reading(ec_fsm_t *);
-void ec_fsm_slave_read_status(ec_fsm_t *);
-void ec_fsm_slave_read_base(ec_fsm_t *);
-void ec_fsm_slave_read_dl(ec_fsm_t *);
-void ec_fsm_slave_eeprom_size(ec_fsm_t *);
-void ec_fsm_slave_fetch_eeprom(ec_fsm_t *);
-void ec_fsm_slave_fetch_eeprom2(ec_fsm_t *);
-void ec_fsm_slave_end(ec_fsm_t *);
-
-void ec_fsm_slave_conf(ec_fsm_t *);
-void ec_fsm_slave_sync(ec_fsm_t *);
-void ec_fsm_slave_preop(ec_fsm_t *);
-void ec_fsm_slave_fmmu(ec_fsm_t *);
-void ec_fsm_slave_saveop(ec_fsm_t *);
-void ec_fsm_slave_op(ec_fsm_t *);
-void ec_fsm_slave_op2(ec_fsm_t *);
+void ec_fsm_master_rewrite_addresses(ec_fsm_t *);
+void ec_fsm_master_configure_slave(ec_fsm_t *);
+void ec_fsm_master_scan_slaves(ec_fsm_t *);
+void ec_fsm_master_write_eeprom(ec_fsm_t *);
+
+void ec_fsm_slavescan_start(ec_fsm_t *);
+void ec_fsm_slavescan_address(ec_fsm_t *);
+void ec_fsm_slavescan_state(ec_fsm_t *);
+void ec_fsm_slavescan_base(ec_fsm_t *);
+void ec_fsm_slavescan_datalink(ec_fsm_t *);
+void ec_fsm_slavescan_eeprom_size(ec_fsm_t *);
+void ec_fsm_slavescan_eeprom_data(ec_fsm_t *);
+void ec_fsm_slavescan_end(ec_fsm_t *);
+
+void ec_fsm_slaveconf_init(ec_fsm_t *);
+void ec_fsm_slaveconf_sync(ec_fsm_t *);
+void ec_fsm_slaveconf_preop(ec_fsm_t *);
+void ec_fsm_slaveconf_fmmu(ec_fsm_t *);
+void ec_fsm_slaveconf_saveop(ec_fsm_t *);
+void ec_fsm_slaveconf_op(ec_fsm_t *);
+void ec_fsm_slaveconf_end(ec_fsm_t *);
 
 void ec_fsm_sii_start_reading(ec_fsm_t *);
 void ec_fsm_sii_read_check(ec_fsm_t *);
@@ -87,7 +85,7 @@
 void ec_fsm_change_status(ec_fsm_t *);
 void ec_fsm_change_code(ec_fsm_t *);
 void ec_fsm_change_ack(ec_fsm_t *);
-void ec_fsm_change_ack2(ec_fsm_t *);
+void ec_fsm_change_check_ack(ec_fsm_t *);
 void ec_fsm_change_end(ec_fsm_t *);
 void ec_fsm_change_error(ec_fsm_t *);
 
@@ -99,7 +97,7 @@
 
 int ec_fsm_init(ec_fsm_t *fsm, /**< finite state machine */
                 ec_master_t *master /**< EtherCAT master */
-                )
+    )
 {
     fsm->master = master;
     fsm->master_state = ec_fsm_master_start;
@@ -107,9 +105,9 @@
     fsm->master_slave_states = EC_SLAVE_STATE_UNKNOWN;
     fsm->master_validation = 0;
 
-    ec_command_init(&fsm->command);
-    if (ec_command_prealloc(&fsm->command, EC_MAX_DATA_SIZE)) {
-        EC_ERR("FSM failed to allocate FSM command.\n");
+    ec_datagram_init(&fsm->datagram);
+    if (ec_datagram_prealloc(&fsm->datagram, EC_MAX_DATA_SIZE)) {
+        EC_ERR("Failed to allocate FSM datagram.\n");
         return -1;
     }
 
@@ -124,7 +122,7 @@
 
 void ec_fsm_clear(ec_fsm_t *fsm /**< finite state machine */)
 {
-    ec_command_clear(&fsm->command);
+    ec_datagram_clear(&fsm->datagram);
 }
 
 /*****************************************************************************/
@@ -162,8 +160,8 @@
 
 void ec_fsm_master_start(ec_fsm_t *fsm)
 {
-    ec_command_brd(&fsm->command, 0x0130, 2);
-    ec_master_queue_command(fsm->master, &fsm->command);
+    ec_datagram_brd(&fsm->datagram, 0x0130, 2);
+    ec_master_queue_datagram(fsm->master, &fsm->datagram);
     fsm->master_state = ec_fsm_master_broadcast;
 }
 
@@ -176,12 +174,12 @@
 
 void ec_fsm_master_broadcast(ec_fsm_t *fsm /**< finite state machine */)
 {
-    ec_command_t *command = &fsm->command;
+    ec_datagram_t *datagram = &fsm->datagram;
     unsigned int topology_change, states_change, i;
     ec_slave_t *slave;
     ec_master_t *master = fsm->master;
 
-    if (command->state != EC_CMD_RECEIVED) {
+    if (datagram->state != EC_CMD_RECEIVED) {
         if (!master->device->link_state) {
             fsm->master_slaves_responding = 0;
             list_for_each_entry(slave, &master->slaves, list) {
@@ -193,12 +191,12 @@
         return;
     }
 
-    topology_change = (command->working_counter !=
+    topology_change = (datagram->working_counter !=
                        fsm->master_slaves_responding);
-    states_change = (EC_READ_U8(command->data) != fsm->master_slave_states);
-
-    fsm->master_slave_states = EC_READ_U8(command->data);
-    fsm->master_slaves_responding = command->working_counter;
+    states_change = (EC_READ_U8(datagram->data) != fsm->master_slave_states);
+
+    fsm->master_slave_states = EC_READ_U8(datagram->data);
+    fsm->master_slaves_responding = datagram->working_counter;
 
     if (topology_change) {
         EC_INFO("%i slave%s responding.\n",
@@ -221,8 +219,8 @@
         printk(".\n");
     }
 
-    // topology change in free-run mode: clear all slaves and scan the bus
-    if (topology_change && master->mode == EC_MASTER_MODE_FREERUN) {
+    // topology change in idle mode: clear all slaves and scan the bus
+    if (topology_change && master->mode == EC_MASTER_MODE_IDLE) {
         EC_INFO("Scanning bus.\n");
 
         ec_master_eoe_stop(master);
@@ -264,17 +262,84 @@
 
         // begin scanning of slaves
         fsm->slave = list_entry(master->slaves.next, ec_slave_t, list);
-        fsm->slave_state = ec_fsm_slave_start_reading;
-        fsm->master_state = ec_fsm_master_scan;
+        fsm->slave_state = ec_fsm_slavescan_start;
+        fsm->master_state = ec_fsm_master_scan_slaves;
         fsm->master_state(fsm); // execute immediately
         return;
     }
 
     // fetch state from each slave
     fsm->slave = list_entry(master->slaves.next, ec_slave_t, list);
-    ec_command_nprd(&fsm->command, fsm->slave->station_address, 0x0130, 2);
-    ec_master_queue_command(master, &fsm->command);
-    fsm->master_state = ec_fsm_master_states;
+    ec_datagram_nprd(&fsm->datagram, fsm->slave->station_address, 0x0130, 2);
+    ec_master_queue_datagram(master, &fsm->datagram);
+    fsm->master_state = ec_fsm_master_read_states;
+}
+
+/*****************************************************************************/
+
+/**
+   Master action: PROC_STATES.
+   Processes the slave states.
+*/
+
+void ec_fsm_master_action_process_states(ec_fsm_t *fsm
+                                         /**< finite state machine */
+                                         )
+{
+    ec_master_t *master = fsm->master;
+    ec_slave_t *slave;
+
+    // check if any slaves are not in the state, they're supposed to be
+    list_for_each_entry(slave, &master->slaves, list) {
+        if (slave->error_flag ||
+            !slave->online ||
+            slave->requested_state == EC_SLAVE_STATE_UNKNOWN ||
+            slave->current_state == slave->requested_state) continue;
+
+        EC_INFO("Changing state of slave %i from ", slave->ring_position);
+        ec_print_states(slave->current_state);
+        printk(" to ");
+        ec_print_states(slave->requested_state);
+        printk(".\n");
+
+        fsm->slave = slave;
+        fsm->slave_state = ec_fsm_slaveconf_init;
+        fsm->change_new = EC_SLAVE_STATE_INIT;
+        fsm->change_state = ec_fsm_change_start;
+        fsm->master_state = ec_fsm_master_configure_slave;
+        fsm->master_state(fsm); // execute immediately
+        return;
+    }
+
+    if (master->mode == EC_MASTER_MODE_IDLE) {
+        // nothing to configure. check for pending EEPROM write operations.
+        list_for_each_entry(slave, &master->slaves, list) {
+            if (!slave->new_eeprom_data) continue;
+
+            if (!slave->online || slave->error_flag) {
+                kfree(slave->new_eeprom_data);
+                slave->new_eeprom_data = NULL;
+                EC_ERR("Discarding EEPROM data, slave %i not ready.\n",
+                       slave->ring_position);
+                continue;
+            }
+
+            // found pending EEPROM write operation. execute it!
+            EC_INFO("Writing EEPROM of slave %i...\n", slave->ring_position);
+            fsm->sii_offset = 0x0000;
+            memcpy(fsm->sii_value, slave->new_eeprom_data, 2);
+            fsm->sii_mode = 1;
+            fsm->sii_state = ec_fsm_sii_start_writing;
+            fsm->slave = slave;
+            fsm->master_state = ec_fsm_master_write_eeprom;
+            fsm->master_state(fsm); // execute immediately
+            return;
+        }
+    }
+
+    // nothing to do. restart master state machine.
+    fsm->master_state = ec_fsm_master_start;
+    fsm->master_state(fsm); // execute immediately
 }
 
 /*****************************************************************************/
@@ -289,37 +354,38 @@
     ec_master_t *master = fsm->master;
     ec_slave_t *slave = fsm->slave;
 
-    // have all states been read?
-    if (slave->list.next == &master->slaves) {
-
-        // check, if a bus validation has to be done
-        if (fsm->master_validation) {
-            fsm->master_validation = 0;
-            list_for_each_entry(slave, &master->slaves, list) {
-                if (slave->online) continue;
-
-                // At least one slave is offline. validate!
-                EC_INFO("Validating bus.\n");
-                fsm->slave = list_entry(master->slaves.next, ec_slave_t, list);
-                fsm->master_state = ec_fsm_master_validate_vendor;
-                fsm->sii_offset = 0x0008; // vendor ID
-                fsm->sii_mode = 0;
-                fsm->sii_state = ec_fsm_sii_start_reading;
-                fsm->sii_state(fsm); // execute immediately
-                return;
-            }
+    // is there another slave to query?
+    if (slave->list.next != &master->slaves) {
+        // process next slave
+        fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list);
+        ec_datagram_nprd(&fsm->datagram, fsm->slave->station_address,
+                         0x0130, 2);
+        ec_master_queue_datagram(master, &fsm->datagram);
+        fsm->master_state = ec_fsm_master_read_states;
+        return;
+    }
+
+    // all slave states read
+
+    // check, if a bus validation has to be done
+    if (fsm->master_validation) {
+        fsm->master_validation = 0;
+        list_for_each_entry(slave, &master->slaves, list) {
+            if (slave->online) continue;
+
+            // At least one slave is offline. validate!
+            EC_INFO("Validating bus.\n");
+            fsm->slave = list_entry(master->slaves.next, ec_slave_t, list);
+            fsm->master_state = ec_fsm_master_validate_vendor;
+            fsm->sii_offset = 0x0008; // vendor ID
+            fsm->sii_mode = 0;
+            fsm->sii_state = ec_fsm_sii_start_reading;
+            fsm->sii_state(fsm); // execute immediately
+            return;
         }
-
-        fsm->master_state = ec_fsm_master_proc_states;
-        fsm->master_state(fsm); // execute immediately
-        return;
-    }
-
-    // process next slave
-    fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list);
-    ec_command_nprd(&fsm->command, fsm->slave->station_address, 0x0130, 2);
-    ec_master_queue_command(master, &fsm->command);
-    fsm->master_state = ec_fsm_master_states;
+    }
+
+    ec_fsm_master_action_process_states(fsm);
 }
 
 /*****************************************************************************/
@@ -329,20 +395,20 @@
    Fetches the AL- and online state of a slave.
 */
 
-void ec_fsm_master_states(ec_fsm_t *fsm /**< finite state machine */)
-{
-    ec_slave_t *slave = fsm->slave;
-    ec_command_t *command = &fsm->command;
+void ec_fsm_master_read_states(ec_fsm_t *fsm /**< finite state machine */)
+{
+    ec_slave_t *slave = fsm->slave;
+    ec_datagram_t *datagram = &fsm->datagram;
     uint8_t new_state;
 
-    if (command->state != EC_CMD_RECEIVED) {
+    if (datagram->state != EC_CMD_RECEIVED) {
         fsm->master_state = ec_fsm_master_start;
         fsm->master_state(fsm); // execute immediately
         return;
     }
 
     // did the slave not respond to its station address?
-    if (command->working_counter != 1) {
+    if (datagram->working_counter != 1) {
         if (slave->online) {
             slave->online = 0;
             EC_INFO("Slave %i: offline.\n", slave->ring_position);
@@ -352,10 +418,10 @@
     }
 
     // slave responded
-    new_state = EC_READ_U8(command->data);
+    new_state = EC_READ_U8(datagram->data);
     if (!slave->online) { // slave was offline before
         slave->online = 1;
-        slave->state_error = 0;
+        slave->error_flag = 0; // clear error flag
         slave->current_state = new_state;
         EC_INFO("Slave %i: online (", slave->ring_position);
         ec_print_states(new_state);
@@ -376,62 +442,6 @@
 /*****************************************************************************/
 
 /**
-   Master state: PROC_STATES.
-   Processes the slave states.
-*/
-
-void ec_fsm_master_proc_states(ec_fsm_t *fsm /**< finite state machine */)
-{
-    ec_master_t *master = fsm->master;
-    ec_slave_t *slave;
-
-    // check if any slaves are not in the state, they're supposed to be
-    list_for_each_entry(slave, &master->slaves, list) {
-        if (slave->state_error || !slave->online ||
-            slave->requested_state == EC_SLAVE_STATE_UNKNOWN ||
-            slave->current_state == slave->requested_state) continue;
-
-        EC_INFO("Changing state of slave %i from ", slave->ring_position);
-        ec_print_states(slave->current_state);
-        printk(" to ");
-        ec_print_states(slave->requested_state);
-        printk(".\n");
-
-        fsm->slave = slave;
-        fsm->slave_state = ec_fsm_slave_conf;
-        fsm->change_new = EC_SLAVE_STATE_INIT;
-        fsm->change_state = ec_fsm_change_start;
-        fsm->master_state = ec_fsm_master_conf;
-        fsm->master_state(fsm); // execute immediately
-        return;
-    }
-
-    if (master->mode == EC_MASTER_MODE_FREERUN) {
-        // nothing to configure. check for pending EEPROM write operations.
-        list_for_each_entry(slave, &master->slaves, list) {
-            if (!slave->new_eeprom_data) continue;
-
-            // found pending EEPROM write operation. execute it!
-            EC_INFO("Writing EEPROM of slave %i...\n", slave->ring_position);
-            fsm->sii_offset = 0x0000;
-            memcpy(fsm->sii_value, slave->new_eeprom_data, 2);
-            fsm->sii_mode = 1;
-            fsm->sii_state = ec_fsm_sii_start_writing;
-            fsm->slave = slave;
-            fsm->master_state = ec_fsm_master_eeprom;
-            fsm->master_state(fsm); // execute immediately
-            return;
-        }
-    }
-
-    // nothing to do. restart master state machine.
-    fsm->master_state = ec_fsm_master_start;
-    fsm->master_state(fsm); // execute immediately
-}
-
-/*****************************************************************************/
-
-/**
    Master state: VALIDATE_VENDOR.
    Validates the vendor ID of a slave.
 */
@@ -443,6 +453,7 @@
     fsm->sii_state(fsm); // execute SII state machine
 
     if (fsm->sii_state == ec_fsm_sii_error) {
+        fsm->slave->error_flag = 1;
         EC_ERR("Failed to validate vendor ID of slave %i.\n",
                slave->ring_position);
         fsm->master_state = ec_fsm_master_start;
@@ -470,62 +481,14 @@
 /*****************************************************************************/
 
 /**
-   Master state: VALIDATE_PRODUCT.
-   Validates the product ID of a slave.
-*/
-
-void ec_fsm_master_validate_product(ec_fsm_t *fsm /**< finite state machine */)
-{
-    ec_slave_t *slave = fsm->slave;
-
-    fsm->sii_state(fsm); // execute SII state machine
-
-    if (fsm->sii_state == ec_fsm_sii_error) {
-        EC_ERR("Failed to validate product code of slave %i.\n",
-               slave->ring_position);
-        fsm->master_state = ec_fsm_master_start;
-        fsm->master_state(fsm); // execute immediately
-        return;
-    }
-
-    if (fsm->sii_state != ec_fsm_sii_end) return;
-
-    if (EC_READ_U32(fsm->sii_value) != slave->sii_product_code) {
-        EC_ERR("Slave %i: invalid product code!\n", slave->ring_position);
-        EC_ERR("expected 0x%08X, got 0x%08X.\n", slave->sii_product_code,
-               EC_READ_U32(fsm->sii_value));
-        fsm->master_state = ec_fsm_master_start;
-        fsm->master_state(fsm); // execute immediately
-        return;
-    }
-
-    // have all states been validated?
-    if (slave->list.next == &fsm->master->slaves) {
-        fsm->slave = list_entry(fsm->master->slaves.next, ec_slave_t, list);
-        fsm->master_state = ec_fsm_master_reconfigure;
-        return;
-    }
-
-    // validate next slave
-    fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list);
-    fsm->master_state = ec_fsm_master_validate_vendor;
-    fsm->sii_offset = 0x0008; // vendor ID
-    fsm->sii_mode = 0;
-    fsm->sii_state = ec_fsm_sii_start_reading;
-    fsm->sii_state(fsm); // execute immediately
-}
-
-/*****************************************************************************/
-
-/**
-   Master state: RECONFIGURE.
+   Master action: ADDRESS.
    Looks for slave, that have lost their configuration and writes
    their station address, so that they can be reconfigured later.
 */
 
-void ec_fsm_master_reconfigure(ec_fsm_t *fsm /**< finite state machine */)
-{
-    ec_command_t *command = &fsm->command;
+void ec_fsm_master_action_addresses(ec_fsm_t *fsm /**< finite state machine */)
+{
+    ec_datagram_t *datagram = &fsm->datagram;
 
     while (fsm->slave->online) {
         if (fsm->slave->list.next == &fsm->master->slaves) { // last slave?
@@ -540,10 +503,60 @@
     EC_INFO("Reinitializing slave %i.\n", fsm->slave->ring_position);
 
     // write station address
-    ec_command_apwr(command, fsm->slave->ring_position, 0x0010, 2);
-    EC_WRITE_U16(command->data, fsm->slave->station_address);
-    ec_master_queue_command(fsm->master, command);
-    fsm->master_state = ec_fsm_master_address;
+    ec_datagram_apwr(datagram, fsm->slave->ring_position, 0x0010, 2);
+    EC_WRITE_U16(datagram->data, fsm->slave->station_address);
+    ec_master_queue_datagram(fsm->master, datagram);
+    fsm->master_state = ec_fsm_master_rewrite_addresses;
+}
+
+/*****************************************************************************/
+
+/**
+   Master state: VALIDATE_PRODUCT.
+   Validates the product ID of a slave.
+*/
+
+void ec_fsm_master_validate_product(ec_fsm_t *fsm /**< finite state machine */)
+{
+    ec_slave_t *slave = fsm->slave;
+
+    fsm->sii_state(fsm); // execute SII state machine
+
+    if (fsm->sii_state == ec_fsm_sii_error) {
+        fsm->slave->error_flag = 1;
+        EC_ERR("Failed to validate product code of slave %i.\n",
+               slave->ring_position);
+        fsm->master_state = ec_fsm_master_start;
+        fsm->master_state(fsm); // execute immediately
+        return;
+    }
+
+    if (fsm->sii_state != ec_fsm_sii_end) return;
+
+    if (EC_READ_U32(fsm->sii_value) != slave->sii_product_code) {
+        EC_ERR("Slave %i: invalid product code!\n", slave->ring_position);
+        EC_ERR("expected 0x%08X, got 0x%08X.\n", slave->sii_product_code,
+               EC_READ_U32(fsm->sii_value));
+        fsm->master_state = ec_fsm_master_start;
+        fsm->master_state(fsm); // execute immediately
+        return;
+    }
+
+    // have all states been validated?
+    if (slave->list.next == &fsm->master->slaves) {
+        fsm->slave = list_entry(fsm->master->slaves.next, ec_slave_t, list);
+        // start writing addresses to offline slaves
+        ec_fsm_master_action_addresses(fsm);
+        return;
+    }
+
+    // validate next slave
+    fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list);
+    fsm->master_state = ec_fsm_master_validate_vendor;
+    fsm->sii_offset = 0x0008; // vendor ID
+    fsm->sii_mode = 0;
+    fsm->sii_state = ec_fsm_sii_start_reading;
+    fsm->sii_state(fsm); // execute immediately
 }
 
 /*****************************************************************************/
@@ -553,12 +566,14 @@
    Checks, if the new station address has been written to the slave.
 */
 
-void ec_fsm_master_address(ec_fsm_t *fsm /**< finite state machine */)
-{
-    ec_slave_t *slave = fsm->slave;
-    ec_command_t *command = &fsm->command;
-
-    if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) {
+void ec_fsm_master_rewrite_addresses(ec_fsm_t *fsm
+                                     /**< finite state machine */
+                                     )
+{
+    ec_slave_t *slave = fsm->slave;
+    ec_datagram_t *datagram = &fsm->datagram;
+
+    if (datagram->state != EC_CMD_RECEIVED || datagram->working_counter != 1) {
         EC_ERR("Failed to write station address on slave %i.\n",
                slave->ring_position);
     }
@@ -571,8 +586,8 @@
 
     // check next slave
     fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list);
-    fsm->master_state = ec_fsm_master_reconfigure;
-    fsm->master_state(fsm); // execute immediately
+    // Write new station address to slave
+    ec_fsm_master_action_addresses(fsm);
 }
 
 /*****************************************************************************/
@@ -582,7 +597,7 @@
    Executes the sub-statemachine for the scanning of a slave.
 */
 
-void ec_fsm_master_scan(ec_fsm_t *fsm /**< finite state machine */)
+void ec_fsm_master_scan_slaves(ec_fsm_t *fsm /**< finite state machine */)
 {
     ec_master_t *master = fsm->master;
     ec_slave_t *slave = fsm->slave;
@@ -592,7 +607,7 @@
 
     fsm->slave_state(fsm); // execute slave state machine
 
-    if (fsm->slave_state != ec_fsm_slave_end) return;
+    if (fsm->slave_state != ec_fsm_slavescan_end) return;
 
     // have all slaves been fetched?
     if (slave->list.next == &master->slaves) {
@@ -619,7 +634,7 @@
             }
 
             if (!slave->type) {
-                EC_WARN("FSM: Unknown slave device (vendor 0x%08X,"
+                EC_WARN("Unknown slave device (vendor 0x%08X,"
                         " code 0x%08X) at position %i.\n",
                         slave->sii_vendor_id, slave->sii_product_code,
                         slave->ring_position);
@@ -636,7 +651,9 @@
             }
 
             // determine initial state.
-            if ((slave->type && slave->type->special == EC_TYPE_BUS_COUPLER)) {
+            if ((slave->type &&
+                 (slave->type->special == EC_TYPE_BUS_COUPLER ||
+                  slave->type->special == EC_TYPE_INFRA))) {
                 slave->requested_state = EC_SLAVE_STATE_OP;
             }
             else {
@@ -645,7 +662,7 @@
                 else
                     slave->requested_state = EC_SLAVE_STATE_INIT;
             }
-            slave->state_error = 0;
+            slave->error_flag = 0;
 
             // calculate coupler-based slave address
             slave->coupler_index = current_coupler_index;
@@ -653,7 +670,7 @@
             coupler_subindex++;
         }
 
-        if (master->mode == EC_MASTER_MODE_FREERUN) {
+        if (master->mode == EC_MASTER_MODE_IDLE) {
             // start EoE processing
             ec_master_eoe_start(master);
         }
@@ -665,7 +682,7 @@
 
     // process next slave
     fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list);
-    fsm->slave_state = ec_fsm_slave_start_reading;
+    fsm->slave_state = ec_fsm_slavescan_start;
     fsm->slave_state(fsm); // execute immediately
 }
 
@@ -676,12 +693,14 @@
    Starts configuring a slave.
 */
 
-void ec_fsm_master_conf(ec_fsm_t *fsm /**< finite state machine */)
+void ec_fsm_master_configure_slave(ec_fsm_t *fsm
+                                   /**< finite state machine */
+                                   )
 {
     fsm->slave_state(fsm); // execute slave's state machine
-    if (fsm->slave_state != ec_fsm_slave_end) return;
-    fsm->master_state = ec_fsm_master_proc_states;
-    fsm->master_state(fsm); // execute immediately
+    if (fsm->slave_state != ec_fsm_slaveconf_end) return;
+
+    ec_fsm_master_action_process_states(fsm);
 }
 
 /*****************************************************************************/
@@ -690,13 +709,14 @@
    Master state: EEPROM.
 */
 
-void ec_fsm_master_eeprom(ec_fsm_t *fsm /**< finite state machine */)
+void ec_fsm_master_write_eeprom(ec_fsm_t *fsm /**< finite state machine */)
 {
     ec_slave_t *slave = fsm->slave;
 
     fsm->sii_state(fsm); // execute SII state machine
 
     if (fsm->sii_state == ec_fsm_sii_error) {
+        fsm->slave->error_flag = 1;
         EC_ERR("Failed to write EEPROM contents to slave %i.\n",
                slave->ring_position);
         kfree(slave->new_eeprom_data);
@@ -722,13 +742,13 @@
     slave->new_eeprom_data = NULL;
 
     // restart master state machine.
-    fsm->master_state = ec_fsm_master_start;
+    fsm->master_state = ec_fsm_master_start; // TODO: Evaluate new contents!
     fsm->master_state(fsm); // execute immediately
     return;
 }
 
 /******************************************************************************
- *  slave state machine
+ *  slave scan sub state machine
  *****************************************************************************/
 
 /**
@@ -737,126 +757,129 @@
    slave, according to its ring position.
 */
 
-void ec_fsm_slave_start_reading(ec_fsm_t *fsm /**< finite state machine */)
-{
-    ec_command_t *command = &fsm->command;
+void ec_fsm_slavescan_start(ec_fsm_t *fsm /**< finite state machine */)
+{
+    ec_datagram_t *datagram = &fsm->datagram;
 
     // write station address
-    ec_command_apwr(command, fsm->slave->ring_position, 0x0010, 2);
-    EC_WRITE_U16(command->data, fsm->slave->station_address);
-    ec_master_queue_command(fsm->master, command);
-    fsm->slave_state = ec_fsm_slave_read_status;
-}
-
-/*****************************************************************************/
-
-/**
-   Slave state: READ_STATUS.
-*/
-
-void ec_fsm_slave_read_status(ec_fsm_t *fsm /**< finite state machine */)
-{
-    ec_command_t *command = &fsm->command;
-
-    if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) {
-        EC_ERR("FSM failed to write station address of slave %i.\n",
+    ec_datagram_apwr(datagram, fsm->slave->ring_position, 0x0010, 2);
+    EC_WRITE_U16(datagram->data, fsm->slave->station_address);
+    ec_master_queue_datagram(fsm->master, datagram);
+    fsm->slave_state = ec_fsm_slavescan_address;
+}
+
+/*****************************************************************************/
+
+/**
+   Slave state: ADDRESS.
+*/
+
+void ec_fsm_slavescan_address(ec_fsm_t *fsm /**< finite state machine */)
+{
+    ec_datagram_t *datagram = &fsm->datagram;
+
+    if (datagram->state != EC_CMD_RECEIVED || datagram->working_counter != 1) {
+        fsm->slave->error_flag = 1;
+        fsm->slave_state = ec_fsm_slavescan_end;
+        EC_ERR("Failed to write station address of slave %i.\n",
                fsm->slave->ring_position);
-        fsm->slave_state = ec_fsm_slave_end;
-        return;
-    }
-
-    // read AL status
-    ec_command_nprd(command, fsm->slave->station_address, 0x0130, 2);
-    ec_master_queue_command(fsm->master, command);
-    fsm->slave_state = ec_fsm_slave_read_base;
-}
-
-/*****************************************************************************/
-
-/**
-   Slave state: READ_BASE.
-*/
-
-void ec_fsm_slave_read_base(ec_fsm_t *fsm /**< finite state machine */)
-{
-    ec_command_t *command = &fsm->command;
-    ec_slave_t *slave = fsm->slave;
-
-    if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) {
-        EC_ERR("FSM failed to read AL status of slave %i.\n",
+        return;
+    }
+
+    // Read AL state
+    ec_datagram_nprd(datagram, fsm->slave->station_address, 0x0130, 2);
+    ec_master_queue_datagram(fsm->master, datagram);
+    fsm->slave_state = ec_fsm_slavescan_state;
+}
+
+/*****************************************************************************/
+
+/**
+   Slave state: STATE.
+*/
+
+void ec_fsm_slavescan_state(ec_fsm_t *fsm /**< finite state machine */)
+{
+    ec_datagram_t *datagram = &fsm->datagram;
+    ec_slave_t *slave = fsm->slave;
+
+    if (datagram->state != EC_CMD_RECEIVED || datagram->working_counter != 1) {
+        fsm->slave->error_flag = 1;
+        fsm->slave_state = ec_fsm_slavescan_end;
+        EC_ERR("Failed to read AL state of slave %i.\n",
                fsm->slave->ring_position);
-        fsm->slave_state = ec_fsm_slave_end;
-        return;
-    }
-
-    slave->current_state = EC_READ_U8(command->data);
+        return;
+    }
+
+    slave->current_state = EC_READ_U8(datagram->data);
     if (slave->current_state & EC_ACK) {
-        EC_WARN("Slave %i has status error bit set (0x%02X)!\n",
+        EC_WARN("Slave %i has state error bit set (0x%02X)!\n",
                 slave->ring_position, slave->current_state);
         slave->current_state &= 0x0F;
     }
 
     // read base data
-    ec_command_nprd(command, fsm->slave->station_address, 0x0000, 6);
-    ec_master_queue_command(fsm->master, command);
-    fsm->slave_state = ec_fsm_slave_read_dl;
-}
-
-/*****************************************************************************/
-
-/**
-   Slave state: READ_DL.
-*/
-
-void ec_fsm_slave_read_dl(ec_fsm_t *fsm /**< finite state machine */)
-{
-    ec_command_t *command = &fsm->command;
-    ec_slave_t *slave = fsm->slave;
-
-    if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) {
-        EC_ERR("FSM failed to read base data of slave %i.\n",
+    ec_datagram_nprd(datagram, fsm->slave->station_address, 0x0000, 6);
+    ec_master_queue_datagram(fsm->master, datagram);
+    fsm->slave_state = ec_fsm_slavescan_base;
+}
+
+/*****************************************************************************/
+
+/**
+   Slave state: BASE.
+*/
+
+void ec_fsm_slavescan_base(ec_fsm_t *fsm /**< finite state machine */)
+{
+    ec_datagram_t *datagram = &fsm->datagram;
+    ec_slave_t *slave = fsm->slave;
+
+    if (datagram->state != EC_CMD_RECEIVED || datagram->working_counter != 1) {
+        fsm->slave->error_flag = 1;
+        fsm->slave_state = ec_fsm_slavescan_end;
+        EC_ERR("Failed to read base data of slave %i.\n",
                slave->ring_position);
-        fsm->slave_state = ec_fsm_slave_end;
-        return;
-    }
-
-    slave->base_type       = EC_READ_U8 (command->data);
-    slave->base_revision   = EC_READ_U8 (command->data + 1);
-    slave->base_build      = EC_READ_U16(command->data + 2);
-    slave->base_fmmu_count = EC_READ_U8 (command->data + 4);
-    slave->base_sync_count = EC_READ_U8 (command->data + 5);
+        return;
+    }
+
+    slave->base_type       = EC_READ_U8 (datagram->data);
+    slave->base_revision   = EC_READ_U8 (datagram->data + 1);
+    slave->base_build      = EC_READ_U16(datagram->data + 2);
+    slave->base_fmmu_count = EC_READ_U8 (datagram->data + 4);
+    slave->base_sync_count = EC_READ_U8 (datagram->data + 5);
 
     if (slave->base_fmmu_count > EC_MAX_FMMUS)
         slave->base_fmmu_count = EC_MAX_FMMUS;
 
     // read data link status
-    ec_command_nprd(command, slave->station_address, 0x0110, 2);
-    ec_master_queue_command(slave->master, command);
-    fsm->slave_state = ec_fsm_slave_eeprom_size;
-}
-
-/*****************************************************************************/
-
-/**
-   Slave state: EEPROM_SIZE.
-   Read the actual size of the EEPROM to allocate the EEPROM image.
-*/
-
-void ec_fsm_slave_eeprom_size(ec_fsm_t *fsm /**< finite state machine */)
-{
-    ec_command_t *command = &fsm->command;
+    ec_datagram_nprd(datagram, slave->station_address, 0x0110, 2);
+    ec_master_queue_datagram(slave->master, datagram);
+    fsm->slave_state = ec_fsm_slavescan_datalink;
+}
+
+/*****************************************************************************/
+
+/**
+   Slave state: DATALINK.
+*/
+
+void ec_fsm_slavescan_datalink(ec_fsm_t *fsm /**< finite state machine */)
+{
+    ec_datagram_t *datagram = &fsm->datagram;
     ec_slave_t *slave = fsm->slave;
     uint16_t dl_status;
     unsigned int i;
 
-    if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) {
-        EC_ERR("FSM failed to read DL status of slave %i.\n",
+    if (datagram->state != EC_CMD_RECEIVED || datagram->working_counter != 1) {
+        fsm->slave->error_flag = 1;
+        fsm->slave_state = ec_fsm_slavescan_end;
+        EC_ERR("Failed to read DL status of slave %i.\n",
                slave->ring_position);
-        fsm->slave_state = ec_fsm_slave_end;
-        return;
-    }
-
-    dl_status = EC_READ_U16(command->data);
+        return;
+    }
+
+    dl_status = EC_READ_U16(datagram->data);
     for (i = 0; i < 4; i++) {
         slave->dl_link[i] = dl_status & (1 << (4 + i)) ? 1 : 0;
         slave->dl_loop[i] = dl_status & (1 << (8 + i * 2)) ? 1 : 0;
@@ -868,17 +891,17 @@
     fsm->sii_offset = 0x0040; // first category header
     fsm->sii_mode = 1;
     fsm->sii_state = ec_fsm_sii_start_reading;
-    fsm->slave_state = ec_fsm_slave_fetch_eeprom;
+    fsm->slave_state = ec_fsm_slavescan_eeprom_size;
     fsm->slave_state(fsm); // execute state immediately
 }
 
 /*****************************************************************************/
 
 /**
-   Slave state: FETCH_EEPROM.
-*/
-
-void ec_fsm_slave_fetch_eeprom(ec_fsm_t *fsm /**< finite state machine */)
+   Slave state: EEPROM_SIZE.
+*/
+
+void ec_fsm_slavescan_eeprom_size(ec_fsm_t *fsm /**< finite state machine */)
 {
     ec_slave_t *slave = fsm->slave;
     uint16_t cat_type, cat_size;
@@ -887,7 +910,8 @@
     fsm->sii_state(fsm);
 
     if (fsm->sii_state == ec_fsm_sii_error) {
-        fsm->slave_state = ec_fsm_slave_end;
+        fsm->slave->error_flag = 1;
+        fsm->slave_state = ec_fsm_slavescan_end;
         EC_ERR("Failed to read EEPROM size of slave %i.\n",
                slave->ring_position);
         return;
@@ -915,9 +939,10 @@
 
     if (!(slave->eeprom_data =
           (uint8_t *) kmalloc(slave->eeprom_size, GFP_ATOMIC))) {
+        fsm->slave->error_flag = 1;
+        fsm->slave_state = ec_fsm_slavescan_end;
         EC_ERR("Failed to allocate EEPROM data on slave %i.\n",
                slave->ring_position);
-        fsm->slave_state = ec_fsm_slave_end;
         return;
     }
 
@@ -926,17 +951,17 @@
     fsm->sii_offset = 0x0000;
     fsm->sii_mode = 1;
     fsm->sii_state = ec_fsm_sii_start_reading;
-    fsm->slave_state = ec_fsm_slave_fetch_eeprom2;
+    fsm->slave_state = ec_fsm_slavescan_eeprom_data;
     fsm->slave_state(fsm); // execute state immediately
 }
 
 /*****************************************************************************/
 
 /**
-   Slave state: FETCH_EEPROM2.
-*/
-
-void ec_fsm_slave_fetch_eeprom2(ec_fsm_t *fsm /**< finite state machine */)
+   Slave state: EEPROM_DATA.
+*/
+
+void ec_fsm_slavescan_eeprom_data(ec_fsm_t *fsm /**< finite state machine */)
 {
     ec_slave_t *slave = fsm->slave;
     uint16_t *cat_word, cat_type, cat_size;
@@ -945,7 +970,8 @@
     fsm->sii_state(fsm);
 
     if (fsm->sii_state == ec_fsm_sii_error) {
-        fsm->slave_state = ec_fsm_slave_end;
+        fsm->slave->error_flag = 1;
+        fsm->slave_state = ec_fsm_slavescan_end;
         EC_ERR("Failed to fetch EEPROM contents of slave %i.\n",
                slave->ring_position);
         return;
@@ -1033,26 +1059,45 @@
         cat_word += cat_size + 2;
     }
 
- end:
-    fsm->slave_state = ec_fsm_slave_end;
-}
-
-/*****************************************************************************/
-
-/**
-   Slave state: CONF.
-*/
-
-void ec_fsm_slave_conf(ec_fsm_t *fsm /**< finite state machine */)
-{
-    ec_slave_t *slave = fsm->slave;
-    ec_master_t *master = fsm->master;
-    ec_command_t *command = &fsm->command;
+    fsm->slave_state = ec_fsm_slavescan_end;
+
+end:
+    fsm->slave->error_flag = 1;
+    fsm->slave_state = ec_fsm_slavescan_end;
+}
+
+/*****************************************************************************/
+
+/**
+   Slave state: END.
+   End state of the slave state machine.
+*/
+
+void ec_fsm_slavescan_end(ec_fsm_t *fsm /**< finite state machine */)
+{
+}
+
+/******************************************************************************
+ *  slave configuration sub state machine
+ *****************************************************************************/
+
+/**
+   Slave state: INIT.
+*/
+
+void ec_fsm_slaveconf_init(ec_fsm_t *fsm /**< finite state machine */)
+{
+    ec_slave_t *slave = fsm->slave;
+    ec_datagram_t *datagram = &fsm->datagram;
+    const ec_sync_t *sync;
+    ec_eeprom_sync_t *eeprom_sync, mbox_sync;
+    unsigned int j;
 
     fsm->change_state(fsm); // execute state change state machine
 
     if (fsm->change_state == ec_fsm_change_error) {
-        fsm->slave_state = ec_fsm_slave_end;
+        slave->error_flag = 1;
+        fsm->slave_state = ec_fsm_slaveconf_end;
         return;
     }
 
@@ -1060,7 +1105,7 @@
 
     // slave is now in INIT
     if (slave->current_state == slave->requested_state) {
-        fsm->slave_state = ec_fsm_slave_end;
+        fsm->slave_state = ec_fsm_slaveconf_end; // successful
         return;
     }
 
@@ -1071,150 +1116,114 @@
 
     // check and reset CRC fault counters
     //ec_slave_check_crc(slave);
-
-    if (!slave->base_fmmu_count) { // no fmmus
-        fsm->slave_state = ec_fsm_slave_sync;
-        fsm->slave_state(fsm); // execute immediately
-        return;
-    }
-
-    // reset FMMUs
-    ec_command_npwr(command, slave->station_address, 0x0600,
-                    EC_FMMU_SIZE * slave->base_fmmu_count);
-    memset(command->data, 0x00, EC_FMMU_SIZE * slave->base_fmmu_count);
-    ec_master_queue_command(master, command);
-    fsm->slave_state = ec_fsm_slave_sync;
-}
-
-/*****************************************************************************/
-
-/**
-   Slave state: SYNC.
-   Configure sync managers.
-*/
-
-void ec_fsm_slave_sync(ec_fsm_t *fsm /**< finite state machine */)
-{
-    ec_command_t *command = &fsm->command;
-    ec_slave_t *slave = fsm->slave;
-    unsigned int j;
-    const ec_sync_t *sync;
-    ec_eeprom_sync_t *eeprom_sync, mbox_sync;
-
-    if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) {
-        EC_ERR("Failed to reset FMMUs of slave %i.\n",
-               slave->ring_position);
-        slave->state_error = 1;
-        fsm->slave_state = ec_fsm_slave_end;
-        return;
-    }
+    // TODO!
 
     if (!slave->base_sync_count) { // no sync managers
-        fsm->slave_state = ec_fsm_slave_preop;
-        fsm->slave_state(fsm); // execute immediately
+        fsm->slave_state = ec_fsm_slaveconf_preop;
+        fsm->change_new = EC_SLAVE_STATE_PREOP;
+        fsm->change_state = ec_fsm_change_start;
+        fsm->change_state(fsm); // execute immediately
         return;
     }
 
     // configure sync managers
-    ec_command_npwr(command, slave->station_address, 0x0800,
-                    EC_SYNC_SIZE * slave->base_sync_count);
-    memset(command->data, 0x00, EC_SYNC_SIZE * slave->base_sync_count);
+    ec_datagram_npwr(datagram, slave->station_address, 0x0800,
+                     EC_SYNC_SIZE * slave->base_sync_count);
+    memset(datagram->data, 0x00, EC_SYNC_SIZE * slave->base_sync_count);
+
+    // does the slave supply sync manager configurations in its EEPROM?
+    if (!list_empty(&slave->eeprom_syncs)) {
+        list_for_each_entry(eeprom_sync, &slave->eeprom_syncs, list) {
+            if (eeprom_sync->index >= slave->base_sync_count) {
+                fsm->slave->error_flag = 1;
+                fsm->slave_state = ec_fsm_slaveconf_end;
+                EC_ERR("Invalid sync manager configuration found!");
+                return;
+            }
+            ec_eeprom_sync_config(eeprom_sync, slave,
+                                  datagram->data + EC_SYNC_SIZE
+                                  * eeprom_sync->index);
+        }
+    }
 
     // known slave type, take type's SM information
-    if (slave->type) {
+    else if (slave->type) {
         for (j = 0; slave->type->sync_managers[j] && j < EC_MAX_SYNC; j++) {
             sync = slave->type->sync_managers[j];
-            ec_sync_config(sync, slave, command->data + EC_SYNC_SIZE * j);
+            ec_sync_config(sync, slave, datagram->data + EC_SYNC_SIZE * j);
         }
     }
 
     // unknown type, but slave has mailbox
     else if (slave->sii_mailbox_protocols)
     {
-        // does it supply sync manager configurations in its EEPROM?
-        if (!list_empty(&slave->eeprom_syncs)) {
-            list_for_each_entry(eeprom_sync, &slave->eeprom_syncs, list) {
-                if (eeprom_sync->index >= slave->base_sync_count) {
-                    EC_ERR("Invalid sync manager configuration found!");
-                    fsm->slave_state = ec_fsm_slave_end;
-                    return;
-                }
-                ec_eeprom_sync_config(eeprom_sync,
-                                      command->data + EC_SYNC_SIZE
-                                      * eeprom_sync->index);
-            }
-        }
-
-        // no sync manager information; guess mailbox settings
-        else {
-            mbox_sync.physical_start_address =
-                slave->sii_rx_mailbox_offset;
-            mbox_sync.length = slave->sii_rx_mailbox_size;
-            mbox_sync.control_register = 0x26;
-            mbox_sync.enable = 1;
-            ec_eeprom_sync_config(&mbox_sync, command->data);
-
-            mbox_sync.physical_start_address =
-                slave->sii_tx_mailbox_offset;
-            mbox_sync.length = slave->sii_tx_mailbox_size;
-            mbox_sync.control_register = 0x22;
-            mbox_sync.enable = 1;
-            ec_eeprom_sync_config(&mbox_sync,
-                                  command->data + EC_SYNC_SIZE);
-        }
+        // guess mailbox settings
+        mbox_sync.physical_start_address =
+            slave->sii_rx_mailbox_offset;
+        mbox_sync.length = slave->sii_rx_mailbox_size;
+        mbox_sync.control_register = 0x26;
+        mbox_sync.enable = 1;
+        ec_eeprom_sync_config(&mbox_sync, slave, datagram->data);
+
+        mbox_sync.physical_start_address =
+            slave->sii_tx_mailbox_offset;
+        mbox_sync.length = slave->sii_tx_mailbox_size;
+        mbox_sync.control_register = 0x22;
+        mbox_sync.enable = 1;
+        ec_eeprom_sync_config(&mbox_sync, slave,
+                              datagram->data + EC_SYNC_SIZE);
 
         EC_INFO("Mailbox configured for unknown slave %i\n",
                 slave->ring_position);
     }
 
-    ec_master_queue_command(fsm->master, command);
-    fsm->slave_state = ec_fsm_slave_preop;
-}
-
-/*****************************************************************************/
-
-/**
-   Slave state: PREOP.
-   Change slave state to PREOP.
-*/
-
-void ec_fsm_slave_preop(ec_fsm_t *fsm /**< finite state machine */)
-{
-    ec_command_t *command = &fsm->command;
-    ec_slave_t *slave = fsm->slave;
-
-    if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) {
+    ec_master_queue_datagram(fsm->master, datagram);
+    fsm->slave_state = ec_fsm_slaveconf_sync;
+}
+
+/*****************************************************************************/
+
+/**
+   Slave state: SYNC.
+*/
+
+void ec_fsm_slaveconf_sync(ec_fsm_t *fsm /**< finite state machine */)
+{
+    ec_datagram_t *datagram = &fsm->datagram;
+    ec_slave_t *slave = fsm->slave;
+
+    if (datagram->state != EC_CMD_RECEIVED || datagram->working_counter != 1) {
+        slave->error_flag = 1;
+        fsm->slave_state = ec_fsm_slaveconf_end;
         EC_ERR("Failed to set sync managers on slave %i.\n",
                slave->ring_position);
-        slave->state_error = 1;
-        fsm->slave_state = ec_fsm_slave_end;
-        return;
-    }
-
+        return;
+    }
+
+    fsm->slave_state = ec_fsm_slaveconf_preop;
     fsm->change_new = EC_SLAVE_STATE_PREOP;
     fsm->change_state = ec_fsm_change_start;
-    fsm->slave_state = ec_fsm_slave_fmmu;
     fsm->change_state(fsm); // execute immediately
 }
 
 /*****************************************************************************/
 
 /**
-   Slave state: FMMU.
-   Configure FMMUs.
-*/
-
-void ec_fsm_slave_fmmu(ec_fsm_t *fsm /**< finite state machine */)
+   Slave state: PREOP.
+*/
+
+void ec_fsm_slaveconf_preop(ec_fsm_t *fsm /**< finite state machine */)
 {
     ec_slave_t *slave = fsm->slave;
     ec_master_t *master = fsm->master;
-    ec_command_t *command = &fsm->command;
+    ec_datagram_t *datagram = &fsm->datagram;
     unsigned int j;
 
     fsm->change_state(fsm); // execute state change state machine
 
     if (fsm->change_state == ec_fsm_change_error) {
-        fsm->slave_state = ec_fsm_slave_end;
+        slave->error_flag = 1;
+        fsm->slave_state = ec_fsm_slaveconf_end;
         return;
     }
 
@@ -1222,57 +1231,57 @@
 
     // slave is now in PREOP
     if (slave->current_state == slave->requested_state) {
-        fsm->slave_state = ec_fsm_slave_end;
+        fsm->slave_state = ec_fsm_slaveconf_end; // successful
         return;
     }
 
     // stop activation here for slaves without type
     if (!slave->type) {
-        fsm->slave_state = ec_fsm_slave_end;
+        fsm->slave_state = ec_fsm_slaveconf_end; // successful
         return;
     }
 
     if (!slave->base_fmmu_count) {
-        fsm->slave_state = ec_fsm_slave_saveop;
-        fsm->slave_state(fsm); // execute immediately
+        fsm->slave_state = ec_fsm_slaveconf_saveop;
+        fsm->change_new = EC_SLAVE_STATE_SAVEOP;
+        fsm->change_state = ec_fsm_change_start;
+        fsm->change_state(fsm); // execute immediately
         return;
     }
 
     // configure FMMUs
-    ec_command_npwr(command, slave->station_address,
-                    0x0600, EC_FMMU_SIZE * slave->base_fmmu_count);
-    memset(command->data, 0x00, EC_FMMU_SIZE * slave->base_fmmu_count);
+    ec_datagram_npwr(datagram, slave->station_address,
+                     0x0600, EC_FMMU_SIZE * slave->base_fmmu_count);
+    memset(datagram->data, 0x00, EC_FMMU_SIZE * slave->base_fmmu_count);
     for (j = 0; j < slave->fmmu_count; j++) {
         ec_fmmu_config(&slave->fmmus[j], slave,
-                       command->data + EC_FMMU_SIZE * j);
-    }
-
-    ec_master_queue_command(master, command);
-    fsm->slave_state = ec_fsm_slave_saveop;
-}
-
-/*****************************************************************************/
-
-/**
-   Slave state: SAVEOP.
-   Set slave state to SAVEOP.
-*/
-
-void ec_fsm_slave_saveop(ec_fsm_t *fsm /**< finite state machine */)
-{
-    ec_command_t *command = &fsm->command;
-
-    if (fsm->slave->base_fmmu_count && (command->state != EC_CMD_RECEIVED ||
-                                        command->working_counter != 1)) {
-        EC_ERR("FSM failed to set FMMUs on slave %i.\n",
+                       datagram->data + EC_FMMU_SIZE * j);
+    }
+
+    ec_master_queue_datagram(master, datagram);
+    fsm->slave_state = ec_fsm_slaveconf_fmmu;
+}
+
+/*****************************************************************************/
+
+/**
+   Slave state: FMMU.
+*/
+
+void ec_fsm_slaveconf_fmmu(ec_fsm_t *fsm /**< finite state machine */)
+{
+    ec_datagram_t *datagram = &fsm->datagram;
+
+    if (datagram->state != EC_CMD_RECEIVED || datagram->working_counter != 1) {
+        fsm->slave->error_flag = 1;
+        fsm->slave_state = ec_fsm_slaveconf_end;
+        EC_ERR("Failed to set FMMUs on slave %i.\n",
                fsm->slave->ring_position);
-        fsm->slave->state_error = 1;
-        fsm->slave_state = ec_fsm_slave_end;
         return;
     }
 
     // set state to SAVEOP
-    fsm->slave_state = ec_fsm_slave_op;
+    fsm->slave_state = ec_fsm_slaveconf_saveop;
     fsm->change_new = EC_SLAVE_STATE_SAVEOP;
     fsm->change_state = ec_fsm_change_start;
     fsm->change_state(fsm); // execute immediately
@@ -1281,16 +1290,16 @@
 /*****************************************************************************/
 
 /**
-   Slave state: OP.
-   Set slave state to OP.
-*/
-
-void ec_fsm_slave_op(ec_fsm_t *fsm /**< finite state machine */)
+   Slave state: SAVEOP.
+*/
+
+void ec_fsm_slaveconf_saveop(ec_fsm_t *fsm /**< finite state machine */)
 {
     fsm->change_state(fsm); // execute state change state machine
 
     if (fsm->change_state == ec_fsm_change_error) {
-        fsm->slave_state = ec_fsm_slave_end;
+        fsm->slave->error_flag = 1;
+        fsm->slave_state = ec_fsm_slaveconf_end;
         return;
     }
 
@@ -1298,12 +1307,12 @@
 
     // slave is now in SAVEOP
     if (fsm->slave->current_state == fsm->slave->requested_state) {
-        fsm->slave_state = ec_fsm_slave_end;
+        fsm->slave_state = ec_fsm_slaveconf_end; // successful
         return;
     }
 
     // set state to OP
-    fsm->slave_state = ec_fsm_slave_op2;
+    fsm->slave_state = ec_fsm_slaveconf_op;
     fsm->change_new = EC_SLAVE_STATE_OP;
     fsm->change_state = ec_fsm_change_start;
     fsm->change_state(fsm); // execute immediately
@@ -1312,23 +1321,23 @@
 /*****************************************************************************/
 
 /**
-   Slave state: OP2
-   Executes the change state machine, until the OP state is set.
-*/
-
-void ec_fsm_slave_op2(ec_fsm_t *fsm /**< finite state machine */)
+   Slave state: OP
+*/
+
+void ec_fsm_slaveconf_op(ec_fsm_t *fsm /**< finite state machine */)
 {
     fsm->change_state(fsm); // execute state change state machine
 
     if (fsm->change_state == ec_fsm_change_error) {
-        fsm->slave_state = ec_fsm_slave_end;
+        fsm->slave->error_flag = 1;
+        fsm->slave_state = ec_fsm_slaveconf_end;
         return;
     }
 
     if (fsm->change_state != ec_fsm_change_end) return;
 
     // slave is now in OP
-    fsm->slave_state = ec_fsm_slave_end;
+    fsm->slave_state = ec_fsm_slaveconf_end; // successful
 }
 
 /*****************************************************************************/
@@ -1338,12 +1347,12 @@
    End state of the slave state machine.
 */
 
-void ec_fsm_slave_end(ec_fsm_t *fsm /**< finite state machine */)
+void ec_fsm_slaveconf_end(ec_fsm_t *fsm /**< finite state machine */)
 {
 }
 
 /******************************************************************************
- *  SII state machine
+ *  SII sub state machine
  *****************************************************************************/
 
 /**
@@ -1353,20 +1362,20 @@
 
 void ec_fsm_sii_start_reading(ec_fsm_t *fsm /**< finite state machine */)
 {
-    ec_command_t *command = &fsm->command;
+    ec_datagram_t *datagram = &fsm->datagram;
 
     // initiate read operation
     if (fsm->sii_mode) {
-        ec_command_npwr(command, fsm->slave->station_address, 0x502, 4);
+        ec_datagram_npwr(datagram, fsm->slave->station_address, 0x502, 4);
     }
     else {
-        ec_command_apwr(command, fsm->slave->ring_position, 0x502, 4);
-    }
-
-    EC_WRITE_U8 (command->data,     0x00); // read-only access
-    EC_WRITE_U8 (command->data + 1, 0x01); // request read operation
-    EC_WRITE_U16(command->data + 2, fsm->sii_offset);
-    ec_master_queue_command(fsm->master, command);
+        ec_datagram_apwr(datagram, fsm->slave->ring_position, 0x502, 4);
+    }
+
+    EC_WRITE_U8 (datagram->data,     0x00); // read-only access
+    EC_WRITE_U8 (datagram->data + 1, 0x01); // request read operation
+    EC_WRITE_U16(datagram->data + 2, fsm->sii_offset);
+    ec_master_queue_datagram(fsm->master, datagram);
     fsm->sii_state = ec_fsm_sii_read_check;
 }
 
@@ -1374,30 +1383,30 @@
 
 /**
    SII state: READ_CHECK.
-   Checks, if the SII-read-command has been sent and issues a fetch command.
+   Checks, if the SII-read-datagram has been sent and issues a fetch datagram.
 */
 
 void ec_fsm_sii_read_check(ec_fsm_t *fsm /**< finite state machine */)
 {
-    ec_command_t *command = &fsm->command;
-
-    if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) {
-        EC_ERR("SII: Reception of read command failed.\n");
+    ec_datagram_t *datagram = &fsm->datagram;
+
+    if (datagram->state != EC_CMD_RECEIVED || datagram->working_counter != 1) {
+        EC_ERR("SII: Reception of read datagram failed.\n");
         fsm->sii_state = ec_fsm_sii_error;
         return;
     }
 
     fsm->sii_start = get_cycles();
 
-    // issue check/fetch command
+    // issue check/fetch datagram
     if (fsm->sii_mode) {
-        ec_command_nprd(command, fsm->slave->station_address, 0x502, 10);
+        ec_datagram_nprd(datagram, fsm->slave->station_address, 0x502, 10);
     }
     else {
-        ec_command_aprd(command, fsm->slave->ring_position, 0x502, 10);
-    }
-
-    ec_master_queue_command(fsm->master, command);
+        ec_datagram_aprd(datagram, fsm->slave->ring_position, 0x502, 10);
+    }
+
+    ec_master_queue_datagram(fsm->master, datagram);
     fsm->sii_state = ec_fsm_sii_read_fetch;
 }
 
@@ -1405,55 +1414,55 @@
 
 /**
    SII state: READ_FETCH.
-   Fetches the result of an SII-read command.
+   Fetches the result of an SII-read datagram.
 */
 
 void ec_fsm_sii_read_fetch(ec_fsm_t *fsm /**< finite state machine */)
 {
-    ec_command_t *command = &fsm->command;
-
-    if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) {
-        EC_ERR("SII: Reception of check/fetch command failed.\n");
+    ec_datagram_t *datagram = &fsm->datagram;
+
+    if (datagram->state != EC_CMD_RECEIVED || datagram->working_counter != 1) {
+        EC_ERR("SII: Reception of check/fetch datagram failed.\n");
         fsm->sii_state = ec_fsm_sii_error;
         return;
     }
 
     // check "busy bit"
-    if (EC_READ_U8(command->data + 1) & 0x81) {
+    if (EC_READ_U8(datagram->data + 1) & 0x81) {
         // still busy... timeout?
         if (get_cycles() - fsm->sii_start >= (cycles_t) 10 * cpu_khz) {
             EC_ERR("SII: Timeout.\n");
             fsm->sii_state = ec_fsm_sii_error;
 #if 0
             EC_DBG("SII busy: %02X %02X %02X %02X\n",
-                   EC_READ_U8(command->data + 0),
-                   EC_READ_U8(command->data + 1),
-                   EC_READ_U8(command->data + 2),
-                   EC_READ_U8(command->data + 3));
+                   EC_READ_U8(datagram->data + 0),
+                   EC_READ_U8(datagram->data + 1),
+                   EC_READ_U8(datagram->data + 2),
+                   EC_READ_U8(datagram->data + 3));
 #endif
         }
 
-        // issue check/fetch command again
+        // issue check/fetch datagram again
         if (fsm->sii_mode) {
-            ec_command_nprd(command, fsm->slave->station_address, 0x502, 10);
+            ec_datagram_nprd(datagram, fsm->slave->station_address, 0x502, 10);
         }
         else {
-            ec_command_aprd(command, fsm->slave->ring_position, 0x502, 10);
+            ec_datagram_aprd(datagram, fsm->slave->ring_position, 0x502, 10);
         }
-        ec_master_queue_command(fsm->master, command);
+        ec_master_queue_datagram(fsm->master, datagram);
         return;
     }
 
 #if 0
     EC_DBG("SII rec: %02X %02X %02X %02X - %02X %02X %02X %02X\n",
-           EC_READ_U8(command->data + 0), EC_READ_U8(command->data + 1),
-           EC_READ_U8(command->data + 2), EC_READ_U8(command->data + 3),
-           EC_READ_U8(command->data + 6), EC_READ_U8(command->data + 7),
-           EC_READ_U8(command->data + 8), EC_READ_U8(command->data + 9));
+           EC_READ_U8(datagram->data + 0), EC_READ_U8(datagram->data + 1),
+           EC_READ_U8(datagram->data + 2), EC_READ_U8(datagram->data + 3),
+           EC_READ_U8(datagram->data + 6), EC_READ_U8(datagram->data + 7),
+           EC_READ_U8(datagram->data + 8), EC_READ_U8(datagram->data + 9));
 #endif
 
     // SII value received.
-    memcpy(fsm->sii_value, command->data + 6, 4);
+    memcpy(fsm->sii_value, datagram->data + 6, 4);
     fsm->sii_state = ec_fsm_sii_end;
 }
 
@@ -1466,15 +1475,15 @@
 
 void ec_fsm_sii_start_writing(ec_fsm_t *fsm /**< finite state machine */)
 {
-    ec_command_t *command = &fsm->command;
+    ec_datagram_t *datagram = &fsm->datagram;
 
     // initiate write operation
-    ec_command_npwr(command, fsm->slave->station_address, 0x502, 8);
-    EC_WRITE_U8 (command->data,     0x01); // enable write access
-    EC_WRITE_U8 (command->data + 1, 0x02); // request write operation
-    EC_WRITE_U32(command->data + 2, fsm->sii_offset);
-    memcpy(command->data + 6, fsm->sii_value, 2);
-    ec_master_queue_command(fsm->master, command);
+    ec_datagram_npwr(datagram, fsm->slave->station_address, 0x502, 8);
+    EC_WRITE_U8 (datagram->data,     0x01); // enable write access
+    EC_WRITE_U8 (datagram->data + 1, 0x02); // request write operation
+    EC_WRITE_U32(datagram->data + 2, fsm->sii_offset);
+    memcpy(datagram->data + 6, fsm->sii_value, 2);
+    ec_master_queue_datagram(fsm->master, datagram);
     fsm->sii_state = ec_fsm_sii_write_check;
 }
 
@@ -1486,19 +1495,19 @@
 
 void ec_fsm_sii_write_check(ec_fsm_t *fsm /**< finite state machine */)
 {
-    ec_command_t *command = &fsm->command;
-
-    if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) {
-        EC_ERR("SII: Reception of write command failed.\n");
+    ec_datagram_t *datagram = &fsm->datagram;
+
+    if (datagram->state != EC_CMD_RECEIVED || datagram->working_counter != 1) {
+        EC_ERR("SII: Reception of write datagram failed.\n");
         fsm->sii_state = ec_fsm_sii_error;
         return;
     }
 
     fsm->sii_start = get_cycles();
 
-    // issue check/fetch command
-    ec_command_nprd(command, fsm->slave->station_address, 0x502, 2);
-    ec_master_queue_command(fsm->master, command);
+    // issue check/fetch datagram
+    ec_datagram_nprd(datagram, fsm->slave->station_address, 0x502, 2);
+    ec_master_queue_datagram(fsm->master, datagram);
     fsm->sii_state = ec_fsm_sii_write_check2;
 }
 
@@ -1510,25 +1519,25 @@
 
 void ec_fsm_sii_write_check2(ec_fsm_t *fsm /**< finite state machine */)
 {
-    ec_command_t *command = &fsm->command;
-
-    if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) {
-        EC_ERR("SII: Reception of write check command failed.\n");
+    ec_datagram_t *datagram = &fsm->datagram;
+
+    if (datagram->state != EC_CMD_RECEIVED || datagram->working_counter != 1) {
+        EC_ERR("SII: Reception of write check datagram failed.\n");
         fsm->sii_state = ec_fsm_sii_error;
         return;
     }
 
-    if (EC_READ_U8(command->data + 1) & 0x82) {
+    if (EC_READ_U8(datagram->data + 1) & 0x82) {
         // still busy... timeout?
         if (get_cycles() - fsm->sii_start >= (cycles_t) 10 * cpu_khz) {
             EC_ERR("SII: Write timeout.\n");
             fsm->sii_state = ec_fsm_sii_error;
         }
 
-        // issue check/fetch command again
-        ec_master_queue_command(fsm->master, command);
-    }
-    else if (EC_READ_U8(command->data + 1) & 0x40) {
+        // issue check/fetch datagram again
+        ec_master_queue_datagram(fsm->master, datagram);
+    }
+    else if (EC_READ_U8(datagram->data + 1) & 0x40) {
         EC_ERR("SII: Write operation failed!\n");
         fsm->sii_state = ec_fsm_sii_error;
     }
@@ -1560,7 +1569,7 @@
 }
 
 /******************************************************************************
- *  state change state machine
+ *  state change sub state machine
  *****************************************************************************/
 
 /**
@@ -1569,13 +1578,13 @@
 
 void ec_fsm_change_start(ec_fsm_t *fsm /**< finite state machine */)
 {
-    ec_command_t *command = &fsm->command;
+    ec_datagram_t *datagram = &fsm->datagram;
     ec_slave_t *slave = fsm->slave;
 
     // write new state to slave
-    ec_command_npwr(command, slave->station_address, 0x0120, 2);
-    EC_WRITE_U16(command->data, fsm->change_new);
-    ec_master_queue_command(fsm->master, command);
+    ec_datagram_npwr(datagram, slave->station_address, 0x0120, 2);
+    EC_WRITE_U16(datagram->data, fsm->change_new);
+    ec_master_queue_datagram(fsm->master, datagram);
     fsm->change_state = ec_fsm_change_check;
 }
 
@@ -1587,53 +1596,50 @@
 
 void ec_fsm_change_check(ec_fsm_t *fsm /**< finite state machine */)
 {
-    ec_command_t *command = &fsm->command;
-    ec_slave_t *slave = fsm->slave;
-
-    if (command->state != EC_CMD_RECEIVED) {
-        EC_ERR("Failed to send state command to slave %i!\n",
+    ec_datagram_t *datagram = &fsm->datagram;
+    ec_slave_t *slave = fsm->slave;
+
+    if (datagram->state != EC_CMD_RECEIVED) {
+        fsm->change_state = ec_fsm_change_error;
+        EC_ERR("Failed to send state datagram to slave %i!\n",
                fsm->slave->ring_position);
-        slave->state_error = 1;
+        return;
+    }
+
+    if (datagram->working_counter != 1) {
         fsm->change_state = ec_fsm_change_error;
-        return;
-    }
-
-    if (command->working_counter != 1) {
         EC_ERR("Failed to set state 0x%02X on slave %i: Slave did not"
                " respond.\n", fsm->change_new, fsm->slave->ring_position);
-        slave->state_error = 1;
+        return;
+    }
+
+    fsm->change_start = get_cycles();
+
+    // read AL status from slave
+    ec_datagram_nprd(datagram, slave->station_address, 0x0130, 2);
+    ec_master_queue_datagram(fsm->master, datagram);
+    fsm->change_state = ec_fsm_change_status;
+}
+
+/*****************************************************************************/
+
+/**
+   Change state: STATUS.
+*/
+
+void ec_fsm_change_status(ec_fsm_t *fsm /**< finite state machine */)
+{
+    ec_datagram_t *datagram = &fsm->datagram;
+    ec_slave_t *slave = fsm->slave;
+
+    if (datagram->state != EC_CMD_RECEIVED || datagram->working_counter != 1) {
         fsm->change_state = ec_fsm_change_error;
-        return;
-    }
-
-    fsm->change_start = get_cycles();
-
-    // read AL status from slave
-    ec_command_nprd(command, slave->station_address, 0x0130, 2);
-    ec_master_queue_command(fsm->master, command);
-    fsm->change_state = ec_fsm_change_status;
-}
-
-/*****************************************************************************/
-
-/**
-   Change state: STATUS.
-*/
-
-void ec_fsm_change_status(ec_fsm_t *fsm /**< finite state machine */)
-{
-    ec_command_t *command = &fsm->command;
-    ec_slave_t *slave = fsm->slave;
-
-    if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) {
         EC_ERR("Failed to check state 0x%02X on slave %i.\n",
                fsm->change_new, slave->ring_position);
-        slave->state_error = 1;
-        fsm->change_state = ec_fsm_change_error;
-        return;
-    }
-
-    slave->current_state = EC_READ_U8(command->data);
+        return;
+    }
+
+    slave->current_state = EC_READ_U8(datagram->data);
 
     if (slave->current_state == fsm->change_new) {
         // state has been set successfully
@@ -1648,15 +1654,14 @@
                " (code 0x%02X)!\n", fsm->change_new, slave->ring_position,
                slave->current_state);
         // fetch AL status error code
-        ec_command_nprd(command, slave->station_address, 0x0134, 2);
-        ec_master_queue_command(fsm->master, command);
+        ec_datagram_nprd(datagram, slave->station_address, 0x0134, 2);
+        ec_master_queue_datagram(fsm->master, datagram);
         fsm->change_state = ec_fsm_change_code;
         return;
     }
 
     if (get_cycles() - fsm->change_start >= (cycles_t) 10 * cpu_khz) {
         // timeout while checking
-        slave->state_error = 1;
         fsm->change_state = ec_fsm_change_error;
         EC_ERR("Timeout while setting state 0x%02X on slave %i.\n",
                fsm->change_new, slave->ring_position);
@@ -1664,8 +1669,8 @@
     }
 
     // still old state: check again
-    ec_command_nprd(command, slave->station_address, 0x0130, 2);
-    ec_master_queue_command(fsm->master, command);
+    ec_datagram_nprd(datagram, slave->station_address, 0x0130, 2);
+    ec_master_queue_datagram(fsm->master, datagram);
 }
 
 /*****************************************************************************/
@@ -1687,10 +1692,24 @@
     {0x0019, "No valid outputs"},
     {0x001A, "Synchronisation error"},
     {0x001B, "Sync manager watchdog"},
+    {0x001C, "Invalid sync manager types"},
+    {0x001D, "Invalid output configuration"},
+    {0x001E, "Invalid input configuration"},
+    {0x001F, "Invalid watchdog configuration"},
     {0x0020, "Slave needs cold start"},
     {0x0021, "Slave needs INIT"},
     {0x0022, "Slave needs PREOP"},
     {0x0023, "Slave needs SAVEOP"},
+    {0x0030, "Invalid DC SYNCH configuration"},
+    {0x0031, "Invalid DC latch configuration"},
+    {0x0032, "PLL error"},
+    {0x0033, "Invalid DC IO error"},
+    {0x0034, "Invalid DC timeout error"},
+    {0x0042, "MBOX EOE"},
+    {0x0043, "MBOX COE"},
+    {0x0044, "MBOX FOE"},
+    {0x0045, "MBOX SOE"},
+    {0x004F, "MBOX VOE"},
     {}
 };
 
@@ -1702,19 +1721,18 @@
 
 void ec_fsm_change_code(ec_fsm_t *fsm /**< finite state machine */)
 {
-    ec_command_t *command = &fsm->command;
+    ec_datagram_t *datagram = &fsm->datagram;
     ec_slave_t *slave = fsm->slave;
     uint32_t code;
     const ec_code_msg_t *al_msg;
 
-    if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) {
-        EC_ERR("Reception of AL status code command failed.\n");
-        slave->state_error = 1;
+    if (datagram->state != EC_CMD_RECEIVED || datagram->working_counter != 1) {
         fsm->change_state = ec_fsm_change_error;
-        return;
-    }
-
-    if ((code = EC_READ_U16(command->data))) {
+        EC_ERR("Reception of AL status code datagram failed.\n");
+        return;
+    }
+
+    if ((code = EC_READ_U16(datagram->data))) {
         for (al_msg = al_status_messages; al_msg->code; al_msg++) {
             if (al_msg->code != code) continue;
             EC_ERR("AL status message 0x%04X: \"%s\".\n",
@@ -1726,9 +1744,9 @@
     }
 
     // acknowledge "old" slave state
-    ec_command_npwr(command, slave->station_address, 0x0120, 2);
-    EC_WRITE_U16(command->data, slave->current_state);
-    ec_master_queue_command(fsm->master, command);
+    ec_datagram_npwr(datagram, slave->station_address, 0x0120, 2);
+    EC_WRITE_U16(datagram->data, slave->current_state);
+    ec_master_queue_datagram(fsm->master, datagram);
     fsm->change_state = ec_fsm_change_ack;
 }
 
@@ -1740,55 +1758,62 @@
 
 void ec_fsm_change_ack(ec_fsm_t *fsm /**< finite state machine */)
 {
-    ec_command_t *command = &fsm->command;
-    ec_slave_t *slave = fsm->slave;
-
-    if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) {
-        EC_ERR("Reception of state ack command failed.\n");
-        slave->state_error = 1;
+    ec_datagram_t *datagram = &fsm->datagram;
+    ec_slave_t *slave = fsm->slave;
+
+    if (datagram->state != EC_CMD_RECEIVED || datagram->working_counter != 1) {
         fsm->change_state = ec_fsm_change_error;
-        return;
-    }
+        EC_ERR("Reception of state ack datagram failed.\n");
+        return;
+    }
+
+    fsm->change_start = get_cycles();
 
     // read new AL status
-    ec_command_nprd(command, slave->station_address, 0x0130, 2);
-    ec_master_queue_command(fsm->master, command);
-    fsm->change_state = ec_fsm_change_ack2;
-}
-
-/*****************************************************************************/
-
-/**
-   Change state: ACK.
-   Acknowledge 2.
-*/
-
-void ec_fsm_change_ack2(ec_fsm_t *fsm /**< finite state machine */)
-{
-    ec_command_t *command = &fsm->command;
-    ec_slave_t *slave = fsm->slave;
-
-    if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) {
-        EC_ERR("Reception of state ack check command failed.\n");
-        slave->state_error = 1;
+    ec_datagram_nprd(datagram, slave->station_address, 0x0130, 2);
+    ec_master_queue_datagram(fsm->master, datagram);
+    fsm->change_state = ec_fsm_change_check_ack;
+}
+
+/*****************************************************************************/
+
+/**
+   Change state: CHECK ACK.
+*/
+
+void ec_fsm_change_check_ack(ec_fsm_t *fsm /**< finite state machine */)
+{
+    ec_datagram_t *datagram = &fsm->datagram;
+    ec_slave_t *slave = fsm->slave;
+    ec_slave_state_t ack_state;
+
+    if (datagram->state != EC_CMD_RECEIVED || datagram->working_counter != 1) {
         fsm->change_state = ec_fsm_change_error;
-        return;
-    }
-
-    slave->current_state = EC_READ_U8(command->data);
-
-    if (slave->current_state == fsm->change_new) {
+        EC_ERR("Reception of state ack check datagram failed.\n");
+        return;
+    }
+
+    ack_state = EC_READ_U8(datagram->data);
+
+    if (ack_state == slave->current_state) {
+        fsm->change_state = ec_fsm_change_error;
         EC_INFO("Acknowleged state 0x%02X on slave %i.\n",
                 slave->current_state, slave->ring_position);
-        slave->state_error = 1;
+        return;
+    }
+
+    if (get_cycles() - fsm->change_start >= (cycles_t) 100 * cpu_khz) {
+        // timeout while checking
+        slave->current_state = EC_SLAVE_STATE_UNKNOWN;
         fsm->change_state = ec_fsm_change_error;
-        return;
-    }
-
-    EC_WARN("Failed to acknowledge state 0x%02X on slave %i"
-            " - Timeout!\n", fsm->change_new, slave->ring_position);
-    slave->state_error = 1;
-    fsm->change_state = ec_fsm_change_error;
+        EC_ERR("Timeout while acknowleging state 0x%02X on slave %i.\n",
+               fsm->change_new, slave->ring_position);
+        return;
+    }
+
+    // reread new AL status
+    ec_datagram_nprd(datagram, slave->station_address, 0x0130, 2);
+    ec_master_queue_datagram(fsm->master, datagram);
 }
 
 /*****************************************************************************/