MERGE branches/async 222:233 -> trunk (Kommando-Warteschlangen).
authorFlorian Pose <fp@igh-essen.com>
Mon, 06 Mar 2006 15:12:34 +0000
changeset 98 f564d0929292
parent 97 e6264685dd7b
child 99 72e375b0b308
MERGE branches/async 222:233 -> trunk (Kommando-Warteschlangen).
devices/8139too.c
include/EtherCAT_dev.h
include/EtherCAT_rt.h
master/Makefile
master/canopen.c
master/command.c
master/command.h
master/device.c
master/device.h
master/domain.c
master/domain.h
master/frame.c
master/frame.h
master/globals.h
master/master.c
master/master.h
master/module.c
master/slave.c
master/slave.h
mini/mini.c
rt/Makefile
rt/msr_module.c
--- a/devices/8139too.c	Thu Mar 02 13:08:07 2006 +0000
+++ b/devices/8139too.c	Mon Mar 06 15:12:34 2006 +0000
@@ -1804,21 +1804,16 @@
 				" (queue head)" : "");
 
 	tp->xstats.tx_timeouts++;
-
-        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
-        printk(KERN_DEBUG "%s: tx_timeout\n", dev->name);
-
-        if (EtherCAT_dev_is_ec(rtl_ec_dev, dev))
-        {
-          EtherCAT_dev_state(rtl_ec_dev, EC_DEVICE_STATE_TIMEOUT);
-        }
+    printk(KERN_DEBUG "%s: tx_timeout\n", dev->name);
 
 	/* disable Tx ASAP, if not already */
 	tmp8 = RTL_R8 (ChipCmd);
 	if (tmp8 & CmdTxEnb)
                 RTL_W8 (ChipCmd, CmdRxEnb);
 
+    /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+
         if (!EtherCAT_dev_is_ec(rtl_ec_dev, dev))
         {
                 spin_lock(&tp->rx_lock);
@@ -1840,7 +1835,7 @@
                 }
 
                 spin_unlock(&tp->rx_lock);
-	}
+        }
         else
         {
                 rtl8139_tx_clear (tp);
@@ -1951,14 +1946,6 @@
 				tp->stats.tx_carrier_errors++;
 			if (txstatus & TxOutOfWindow)
 				tp->stats.tx_window_errors++;
-
-                        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
-                        if (EtherCAT_dev_is_ec(rtl_ec_dev, dev))
-                            EtherCAT_dev_state(rtl_ec_dev, EC_DEVICE_STATE_ERROR);
-
-                        /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
 		} else {
 			if (txstatus & TxUnderrun) {
 				/* Add 64 to the Tx FIFO threshold. */
@@ -2033,15 +2020,6 @@
 		tp->xstats.rx_lost_in_ring++;
 	}
 
-        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
-        if (EtherCAT_dev_is_ec(rtl_ec_dev, dev))
-        {
-          EtherCAT_dev_state(rtl_ec_dev, EC_DEVICE_STATE_ERROR);
-        }
-
-        /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
 #ifndef CONFIG_8139_OLD_RX_RESET
 	tmp8 = RTL_R8 (ChipCmd);
 	RTL_W8 (ChipCmd, tmp8 & ~CmdRxEnb);
--- a/include/EtherCAT_dev.h	Thu Mar 02 13:08:07 2006 +0000
+++ b/include/EtherCAT_dev.h	Mon Mar 06 15:12:34 2006 +0000
@@ -14,23 +14,10 @@
 /*****************************************************************************/
 
 struct ec_device;
-
 typedef struct ec_device ec_device_t;
 
 /*****************************************************************************/
 
-typedef enum
-{
-  EC_DEVICE_STATE_READY = 0,
-  EC_DEVICE_STATE_SENT,
-  EC_DEVICE_STATE_RECEIVED,
-  EC_DEVICE_STATE_TIMEOUT,
-  EC_DEVICE_STATE_ERROR
-}
-ec_device_state_t;
-
-/*****************************************************************************/
-
 ec_device_t *EtherCAT_dev_register(unsigned int, struct net_device *,
                                    irqreturn_t (*)(int, void *,
                                                    struct pt_regs *),
@@ -38,7 +25,6 @@
 void EtherCAT_dev_unregister(unsigned int, ec_device_t *);
 
 int EtherCAT_dev_is_ec(const ec_device_t *, const struct net_device *);
-void EtherCAT_dev_state(ec_device_t *, ec_device_state_t);
 void EtherCAT_dev_receive(ec_device_t *, const void *, size_t);
 void EtherCAT_dev_link_state(ec_device_t *, uint8_t);
 
--- a/include/EtherCAT_rt.h	Thu Mar 02 13:08:07 2006 +0000
+++ b/include/EtherCAT_rt.h	Mon Mar 06 15:12:34 2006 +0000
@@ -63,8 +63,9 @@
                                                 unsigned int timeout_us);
 
 int EtherCAT_rt_master_activate(ec_master_t *master);
+int EtherCAT_rt_master_deactivate(ec_master_t *master);
 
-int EtherCAT_rt_master_deactivate(ec_master_t *master);
+void EtherCAT_rt_master_xio(ec_master_t *master);
 
 void EtherCAT_rt_master_debug(ec_master_t *master, int level);
 void EtherCAT_rt_master_print(const ec_master_t *master);
@@ -81,7 +82,11 @@
                                              unsigned int field_index,
                                              unsigned int field_count);
 
-int EtherCAT_rt_domain_xio(ec_domain_t *domain);
+int EtherCAT_rt_register_domain_fields(ec_domain_t *domain,
+                                       ec_field_init_t *fields);
+
+void EtherCAT_rt_domain_queue(ec_domain_t *domain);
+void EtherCAT_rt_domain_process(ec_domain_t *domain);
 
 /*****************************************************************************/
 // Slave Methods
--- a/master/Makefile	Thu Mar 02 13:08:07 2006 +0000
+++ b/master/Makefile	Mon Mar 06 15:12:34 2006 +0000
@@ -15,13 +15,10 @@
 
 obj-m := ec_master.o
 
-ec_master-objs := module.o master.o device.o slave.o frame.o types.o \
+ec_master-objs := module.o master.o device.o slave.o command.o types.o \
 			domain.o canopen.o
 
-REV = `svnversion $(src)`
-DATE = `date`
-
-EXTRA_CFLAGS = -DEC_REV="$(REV)" -DEC_USER="$(USER)" -DEC_DATE="$(DATE)"
+EXTRA_CFLAGS := -DSVNREV=$(shell svnversion $(src)) -DUSER=$(USER)
 
 #------------------------------------------------------------------------------
 
@@ -48,7 +45,7 @@
 cleandoc:
 	@rm -rf doc
 
-.PHONY: doc
+.PHONY: doc cleandoc modules clean
 
 #------------------------------------------------------------------------------
 
--- a/master/canopen.c	Thu Mar 02 13:08:07 2006 +0000
+++ b/master/canopen.c	Mon Mar 06 15:12:34 2006 +0000
@@ -28,10 +28,11 @@
                                   size_t size /**< Größe des Datenfeldes */
                                   )
 {
-    unsigned char data[0xF6];
-    ec_frame_t frame;
-    unsigned int tries_left, i;
+    uint8_t data[0xF6];
+    ec_command_t command;
+    unsigned int i;
     ec_master_t *master;
+    cycles_t start, end, timeout;
 
     memset(data, 0x00, 0xF6);
 
@@ -56,53 +57,48 @@
         value >>= 8;
     }
 
-    ec_frame_init_npwr(&frame, master, slave->station_address,
-                       0x1800, 0xF6, data);
-
-    if (unlikely(ec_frame_send_receive(&frame))) {
+    ec_command_init_npwr(&command, slave->station_address, 0x1800, 0xF6, data);
+    if (unlikely(ec_master_simple_io(master, &command))) {
         EC_ERR("Mailbox sending failed on slave %i!\n", slave->ring_position);
         return -1;
     }
 
     // Read "written bit" of Sync-Manager
-
-    tries_left = 10;
-    while (tries_left)
-    {
-        ec_frame_init_nprd(&frame, master, slave->station_address, 0x808, 8);
-
-        if (unlikely(ec_frame_send_receive(&frame) < 0)) {
+    start = get_cycles();
+    timeout = cpu_khz; // 1ms
+
+    do
+    {
+        ec_command_init_nprd(&command, slave->station_address, 0x808, 8);
+        if (unlikely(ec_master_simple_io(master, &command))) {
             EC_ERR("Mailbox checking failed on slave %i!\n",
                    slave->ring_position);
             return -1;
         }
 
-        if (EC_READ_U8(frame.data + 5) & 8) { // Written bit is high
-            break;
-        }
-
-        udelay(1000);
-        tries_left--;
-    }
-
-    if (!tries_left) {
+        end = get_cycles();
+
+        if (EC_READ_U8(command.data + 5) & 8) break; // Written bit is high
+    }
+    while ((end - start) < timeout);
+
+    if ((end - start) >= timeout) {
         EC_ERR("Mailbox check - Slave %i timed out.\n", slave->ring_position);
         return -1;
     }
 
-    ec_frame_init_nprd(&frame, master, slave->station_address, 0x18F6, 0xF6);
-
-    if (unlikely(ec_frame_send_receive(&frame) < 0)) {
+    ec_command_init_nprd(&command, slave->station_address, 0x18F6, 0xF6);
+    if (unlikely(ec_master_simple_io(master, &command))) {
         EC_ERR("Mailbox receiving failed on slave %i!\n",
                slave->ring_position);
         return -1;
     }
 
-    if (EC_READ_U8 (frame.data + 5) != 0x03 || // COE
-        EC_READ_U16(frame.data + 6) != 0x3000 || // SDO response
-        EC_READ_U8 (frame.data + 8) >> 5 != 0x03 || // Download response
-        EC_READ_U16(frame.data + 9) != sdo_index || // Index
-        EC_READ_U8 (frame.data + 11) != sdo_subindex) // Subindex
+    if (EC_READ_U8 (command.data + 5) != 0x03 || // COE
+        EC_READ_U16(command.data + 6) != 0x3000 || // SDO response
+        EC_READ_U8 (command.data + 8) >> 5 != 0x03 || // Download response
+        EC_READ_U16(command.data + 9) != sdo_index || // Index
+        EC_READ_U8 (command.data + 11) != sdo_subindex) // Subindex
     {
         EC_ERR("Illegal mailbox response at slave %i!\n",
                slave->ring_position);
@@ -125,12 +121,11 @@
                                  )
 {
     unsigned char data[0xF6];
-    ec_frame_t frame;
-    unsigned int tries_left;
+    ec_command_t command;
     ec_master_t *master;
+    cycles_t start, end, timeout;
 
     memset(data, 0x00, 0xF6);
-
     master = slave->master;
 
     EC_WRITE_U16(data,      0x0006); // Length of the Mailbox service data
@@ -142,60 +137,58 @@
     EC_WRITE_U16(data + 9,  sdo_index);
     EC_WRITE_U8 (data + 11, sdo_subindex);
 
-    ec_frame_init_npwr(&frame, master, slave->station_address,
-                       0x1800, 0xF6, data);
-
-    if (unlikely(ec_frame_send_receive(&frame) < 0)) {
+    ec_command_init_npwr(&command, slave->station_address, 0x1800, 0xF6, data);
+    if (unlikely(ec_master_simple_io(master, &command))) {
         EC_ERR("Mailbox sending failed on slave %i!\n", slave->ring_position);
         return -1;
     }
 
     // Read "written bit" of Sync-Manager
 
-    tries_left = 10;
-    while (tries_left)
-    {
-        ec_frame_init_nprd(&frame, master, slave->station_address, 0x808, 8);
-
-        if (unlikely(ec_frame_send_receive(&frame) < 0)) {
+    start = get_cycles();
+    timeout = cpu_khz; // 1ms
+
+    do
+    {
+        ec_command_init_nprd(&command, slave->station_address, 0x808, 8);
+        if (unlikely(ec_master_simple_io(master, &command))) {
             EC_ERR("Mailbox checking failed on slave %i!\n",
                    slave->ring_position);
             return -1;
         }
 
-        if (EC_READ_U8(frame.data + 5) & 8) { // Written bit is high
+        end = get_cycles();
+
+        if (EC_READ_U8(command.data + 5) & 8) { // Written bit is high
             break;
         }
-
-        udelay(1000);
-        tries_left--;
-    }
-
-    if (!tries_left) {
+    }
+    while (likely((end - start) < timeout));
+
+    if (unlikely((end - start) >= timeout)) {
         EC_ERR("Mailbox check - Slave %i timed out.\n", slave->ring_position);
         return -1;
     }
 
-    ec_frame_init_nprd(&frame, master, slave->station_address, 0x18F6, 0xF6);
-
-    if (unlikely(ec_frame_send_receive(&frame) < 0)) {
+    ec_command_init_nprd(&command, slave->station_address, 0x18F6, 0xF6);
+    if (unlikely(ec_master_simple_io(master, &command))) {
         EC_ERR("Mailbox receiving failed on slave %i!\n",
                slave->ring_position);
         return -1;
     }
 
-    if (EC_READ_U8 (frame.data + 5) != 0x03 || // COE
-        EC_READ_U16(frame.data + 6) != 0x3000 || // SDO response
-        EC_READ_U8 (frame.data + 8) >> 5 != 0x02 || // Upload response
-        EC_READ_U16(frame.data + 9) != sdo_index || // Index
-        EC_READ_U8 (frame.data + 11) != sdo_subindex) // Subindex
+    if (EC_READ_U8 (command.data + 5) != 0x03 || // COE
+        EC_READ_U16(command.data + 6) != 0x3000 || // SDO response
+        EC_READ_U8 (command.data + 8) >> 5 != 0x02 || // Upload response
+        EC_READ_U16(command.data + 9) != sdo_index || // Index
+        EC_READ_U8 (command.data + 11) != sdo_subindex) // Subindex
     {
         EC_ERR("Illegal mailbox response at slave %i!\n",
                slave->ring_position);
         return -1;
     }
 
-    *value = EC_READ_U32(frame.data + 12);
+    *value = EC_READ_U32(command.data + 12);
 
     return 0;
 }
@@ -213,7 +206,8 @@
 int EtherCAT_rt_canopen_sdo_addr_write(ec_master_t *master,
                                        /**< EtherCAT-Master */
                                        const char *addr,
-                                       /**< Addresse, siehe ec_address() */
+                                       /**< Addresse, siehe
+                                          ec_master_slave_address() */
                                        uint16_t index,
                                        /**< SDO-Index */
                                        uint8_t subindex,
@@ -225,7 +219,7 @@
                                        )
 {
     ec_slave_t *slave;
-    if (!(slave = ec_address(master, addr))) return -1;
+    if (!(slave = ec_master_slave_address(master, addr))) return -1;
     return EtherCAT_rt_canopen_sdo_write(slave, index, subindex, value, size);
 }
 
@@ -242,7 +236,8 @@
 int EtherCAT_rt_canopen_sdo_addr_read(ec_master_t *master,
                                       /**< EtherCAT-Slave */
                                       const char *addr,
-                                      /**< Addresse, siehe ec_address() */
+                                      /**< Addresse, siehe
+                                         ec_master_slave_address() */
                                       uint16_t index,
                                       /**< SDO-Index */
                                       uint8_t subindex,
@@ -252,7 +247,7 @@
                                       )
 {
     ec_slave_t *slave;
-    if (!(slave = ec_address(master, addr))) return -1;
+    if (!(slave = ec_master_slave_address(master, addr))) return -1;
     return EtherCAT_rt_canopen_sdo_read(slave, index, subindex, value);
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/master/command.c	Mon Mar 06 15:12:34 2006 +0000
@@ -0,0 +1,235 @@
+/******************************************************************************
+ *
+ *  c o m m a n d . c
+ *
+ *  Methoden für ein EtherCAT-Kommando.
+ *
+ *  $Id$
+ *
+ *****************************************************************************/
+
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include "../include/EtherCAT_si.h"
+#include "command.h"
+#include "master.h"
+
+/*****************************************************************************/
+
+#define EC_FUNC_HEADER \
+    command->index = 0; \
+    command->working_counter = 0; \
+    command->state = EC_CMD_INIT;
+
+#define EC_FUNC_WRITE_FOOTER \
+    command->data_size = data_size; \
+    memcpy(command->data, data, data_size);
+
+#define EC_FUNC_READ_FOOTER \
+    command->data_size = data_size; \
+    memset(command->data, 0x00, data_size);
+
+/*****************************************************************************/
+
+/**
+   Initialisiert ein EtherCAT-NPRD-Kommando.
+
+   Node-adressed physical read.
+*/
+
+void ec_command_init_nprd(ec_command_t *command,
+                          /**< EtherCAT-Rahmen */
+                          uint16_t node_address,
+                          /**< Adresse des Knotens (Slaves) */
+                          uint16_t offset,
+                          /**< Physikalische Speicheradresse im Slave */
+                          size_t data_size
+                          /**< Länge der zu lesenden Daten */
+                          )
+{
+    if (unlikely(node_address == 0x0000))
+        EC_WARN("Using node address 0x0000!\n");
+
+    EC_FUNC_HEADER;
+
+    command->type = EC_CMD_NPRD;
+    command->address.physical.slave = node_address;
+    command->address.physical.mem = offset;
+
+    EC_FUNC_READ_FOOTER;
+}
+
+/*****************************************************************************/
+
+/**
+   Initialisiert ein EtherCAT-NPWR-Kommando.
+
+   Node-adressed physical write.
+*/
+
+void ec_command_init_npwr(ec_command_t *command,
+                          /**< EtherCAT-Rahmen */
+                          uint16_t node_address,
+                          /**< Adresse des Knotens (Slaves) */
+                          uint16_t offset,
+                          /**< Physikalische Speicheradresse im Slave */
+                          size_t data_size,
+                          /**< Länge der zu schreibenden Daten */
+                          const uint8_t *data
+                          /**< Zeiger auf Speicher mit zu schreibenden Daten */
+                          )
+{
+    if (unlikely(node_address == 0x0000))
+        EC_WARN("Using node address 0x0000!\n");
+
+    EC_FUNC_HEADER;
+
+    command->type = EC_CMD_NPWR;
+    command->address.physical.slave = node_address;
+    command->address.physical.mem = offset;
+
+    EC_FUNC_WRITE_FOOTER;
+}
+
+/*****************************************************************************/
+
+/**
+   Initialisiert ein EtherCAT-APRD-Kommando.
+
+   Autoincrement physical read.
+*/
+
+void ec_command_init_aprd(ec_command_t *command,
+                          /**< EtherCAT-Rahmen */
+                          uint16_t ring_position,
+                          /**< Position des Slaves im Bus */
+                          uint16_t offset,
+                          /**< Physikalische Speicheradresse im Slave */
+                          size_t data_size
+                          /**< Länge der zu lesenden Daten */
+                          )
+{
+    EC_FUNC_HEADER;
+
+    command->type = EC_CMD_APRD;
+    command->address.physical.slave = (int16_t) ring_position * (-1);
+    command->address.physical.mem = offset;
+
+    EC_FUNC_READ_FOOTER;
+}
+
+/*****************************************************************************/
+
+/**
+   Initialisiert ein EtherCAT-APWR-Kommando.
+
+   Autoincrement physical write.
+*/
+
+void ec_command_init_apwr(ec_command_t *command,
+                          /**< EtherCAT-Rahmen */
+                          uint16_t ring_position,
+                          /**< Position des Slaves im Bus */
+                          uint16_t offset,
+                          /**< Physikalische Speicheradresse im Slave */
+                          size_t data_size,
+                          /**< Länge der zu schreibenden Daten */
+                          const uint8_t *data
+                          /**< Zeiger auf Speicher mit zu schreibenden Daten */
+                          )
+{
+    EC_FUNC_HEADER;
+
+    command->type = EC_CMD_APWR;
+    command->address.physical.slave = (int16_t) ring_position * (-1);
+    command->address.physical.mem = offset;
+
+    EC_FUNC_WRITE_FOOTER;
+}
+
+/*****************************************************************************/
+
+/**
+   Initialisiert ein EtherCAT-BRD-Kommando.
+
+   Broadcast read.
+*/
+
+void ec_command_init_brd(ec_command_t *command,
+                         /**< EtherCAT-Rahmen */
+                         uint16_t offset,
+                         /**< Physikalische Speicheradresse im Slave */
+                         size_t data_size
+                         /**< Länge der zu lesenden Daten */
+                         )
+{
+    EC_FUNC_HEADER;
+
+    command->type = EC_CMD_BRD;
+    command->address.physical.slave = 0x0000;
+    command->address.physical.mem = offset;
+
+    EC_FUNC_READ_FOOTER;
+}
+
+/*****************************************************************************/
+
+/**
+   Initialisiert ein EtherCAT-BWR-Kommando.
+
+   Broadcast write.
+*/
+
+void ec_command_init_bwr(ec_command_t *command,
+                         /**< EtherCAT-Rahmen */
+                         uint16_t offset,
+                         /**< Physikalische Speicheradresse im Slave */
+                         size_t data_size,
+                         /**< Länge der zu schreibenden Daten */
+                         const uint8_t *data
+                         /**< Zeiger auf Speicher mit zu schreibenden Daten */
+                         )
+{
+    EC_FUNC_HEADER;
+
+    command->type = EC_CMD_BWR;
+    command->address.physical.slave = 0x0000;
+    command->address.physical.mem = offset;
+
+    EC_FUNC_WRITE_FOOTER;
+}
+
+/*****************************************************************************/
+
+/**
+   Initialisiert ein EtherCAT-LRW-Kommando.
+
+   Logical read write.
+*/
+
+void ec_command_init_lrw(ec_command_t *command,
+                         /**< EtherCAT-Rahmen */
+                         uint32_t offset,
+                         /**< Logische Startadresse */
+                         size_t data_size,
+                         /**< Länge der zu lesenden/schreibenden Daten */
+                         uint8_t *data
+                         /**< Zeiger auf die Daten */
+                         )
+{
+    EC_FUNC_HEADER;
+
+    command->type = EC_CMD_LRW;
+    command->address.logical = offset;
+
+    EC_FUNC_WRITE_FOOTER;
+}
+
+/*****************************************************************************/
+
+/* Emacs-Konfiguration
+;;; Local Variables: ***
+;;; c-basic-offset:4 ***
+;;; End: ***
+*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/master/command.h	Mon Mar 06 15:12:34 2006 +0000
@@ -0,0 +1,118 @@
+/******************************************************************************
+ *
+ *  c o m m a n d . h
+ *
+ *  Struktur für ein EtherCAT-Kommando.
+ *
+ *  $Id$
+ *
+ *****************************************************************************/
+
+#ifndef _EC_COMMAND_H_
+#define _EC_COMMAND_H_
+
+#include <linux/list.h>
+
+#include "globals.h"
+
+/*****************************************************************************/
+
+/**
+   EtherCAT-Kommando-Typ.
+*/
+
+typedef enum
+{
+    EC_CMD_NONE = 0x00, /**< Dummy */
+    EC_CMD_APRD = 0x01, /**< Auto-increment physical read */
+    EC_CMD_APWR = 0x02, /**< Auto-increment physical write */
+    EC_CMD_NPRD = 0x04, /**< Node-addressed physical read */
+    EC_CMD_NPWR = 0x05, /**< Node-addressed physical write */
+    EC_CMD_BRD  = 0x07, /**< Broadcast read */
+    EC_CMD_BWR  = 0x08, /**< Broadcast write */
+    EC_CMD_LRW  = 0x0C  /**< Logical read/write */
+}
+ec_command_type_t;
+
+/**
+   EtherCAT-Kommando-Zustand.
+*/
+
+typedef enum
+{
+    EC_CMD_INIT, /**< Neues Kommando */
+    EC_CMD_QUEUED, /**< Kommando in Warteschlange */
+    EC_CMD_SENT, /**< Kommando gesendet */
+    EC_CMD_RECEIVED, /**< Kommando empfangen */
+    EC_CMD_TIMEOUT, /**< Zeitgrenze überschritten */
+    EC_CMD_ERROR /**< Fehler beim Senden oder Empfangen */
+}
+ec_command_state_t;
+
+/*****************************************************************************/
+
+/**
+   EtherCAT-Adresse.
+
+   Im EtherCAT-Kommando sind 4 Bytes für die Adresse reserviert, die je nach
+   Kommandotyp, eine andere Bedeutung haben können: Bei Autoinkrementbefehlen
+   sind die ersten zwei Bytes die (negative) Autoinkrement-Adresse, bei Knoten-
+   adressierten Befehlen entsprechen sie der Knotenadresse. Das dritte und
+   vierte Byte entspricht in diesen Fällen der physikalischen Speicheradresse
+   auf dem Slave. Bei einer logischen Adressierung entsprechen alle vier Bytes
+   der logischen Adresse.
+*/
+
+typedef union
+{
+    struct
+    {
+        uint16_t slave; /**< Adresse des Slaves (Ringposition oder Knoten) */
+        uint16_t mem; /**< Physikalische Speicheradresse im Slave */
+    }
+    physical; /**< Physikalische Adresse */
+
+    uint32_t logical; /**< Logische Adresse */
+}
+ec_address_t;
+
+/*****************************************************************************/
+
+/**
+   EtherCAT-Kommando.
+*/
+
+typedef struct
+{
+    struct list_head list; /**< Nötig für Liste */
+    ec_command_type_t type; /**< Typ des Kommandos (APRD, NPWR, etc) */
+    ec_address_t address; /**< Adresse des/der Empfänger */
+    uint8_t data[EC_MAX_DATA_SIZE]; /**< Kommandodaten */
+    size_t data_size; /**< Länge der zu sendenden und/oder empfangenen Daten */
+    uint8_t index; /**< Kommando-Index, wird vom Master beim Senden gesetzt. */
+    uint16_t working_counter; /**< Working-Counter */
+    ec_command_state_t state; /**< Zustand */
+}
+ec_command_t;
+
+/*****************************************************************************/
+
+void ec_command_init_nprd(ec_command_t *, uint16_t, uint16_t, size_t);
+void ec_command_init_npwr(ec_command_t *, uint16_t, uint16_t, size_t,
+                          const uint8_t *);
+void ec_command_init_aprd(ec_command_t *, uint16_t, uint16_t, size_t);
+void ec_command_init_apwr(ec_command_t *, uint16_t, uint16_t, size_t,
+                          const uint8_t *);
+void ec_command_init_brd(ec_command_t *, uint16_t, size_t);
+void ec_command_init_bwr(ec_command_t *, uint16_t, size_t, const uint8_t *);
+void ec_command_init_lrw(ec_command_t *, uint32_t, size_t, uint8_t *);
+
+/*****************************************************************************/
+
+#endif
+
+/* Emacs-Konfiguration
+;;; Local Variables: ***
+;;; c-basic-offset:4 ***
+;;; End: ***
+*/
--- a/master/device.c	Thu Mar 02 13:08:07 2006 +0000
+++ b/master/device.c	Mon Mar 06 15:12:34 2006 +0000
@@ -19,6 +19,11 @@
 
 /*****************************************************************************/
 
+void ec_data_print(const uint8_t *, size_t);
+void ec_data_print_diff(const uint8_t *, const uint8_t *, size_t);
+
+/*****************************************************************************/
+
 /**
    EtherCAT-Geräte-Konstuktor.
 
@@ -26,26 +31,36 @@
 */
 
 int ec_device_init(ec_device_t *device, /**< EtherCAT-Gerät */
-                   ec_master_t *master /**< Zugehöriger Master */
+                   ec_master_t *master, /**< Zugehöriger Master */
+                   struct net_device *net_dev, /**< Net-Device */
+                   ec_isr_t isr, /**< Adresse der ISR */
+                   struct module *module /**< Modul-Adresse */
                    )
 {
+    struct ethhdr *eth;
+
     device->master = master;
-    device->dev = NULL;
+    device->dev = net_dev;
+    device->isr = isr;
+    device->module = module;
+
     device->open = 0;
-    device->tx_time = 0;
-    device->rx_time = 0;
-    device->state = EC_DEVICE_STATE_READY;
-    device->rx_data_size = 0;
-    device->isr = NULL;
-    device->module = NULL;
-    device->error_reported = 0;
     device->link_state = 0; // down
 
-    if ((device->tx_skb = dev_alloc_skb(ETH_HLEN + EC_MAX_FRAME_SIZE)) == NULL) {
+    if (!(device->tx_skb = dev_alloc_skb(ETH_HLEN + EC_MAX_FRAME_SIZE))) {
         EC_ERR("Error allocating device socket buffer!\n");
         return -1;
     }
 
+    device->tx_skb->dev = net_dev;
+
+    // Ethernet-II-Header hinzufuegen
+    skb_reserve(device->tx_skb, ETH_HLEN);
+    eth = (struct ethhdr *) skb_push(device->tx_skb, ETH_HLEN);
+    eth->h_proto = htons(0x88A4);
+    memcpy(eth->h_source, net_dev->dev_addr, net_dev->addr_len);
+    memset(eth->h_dest, 0xFF, net_dev->addr_len);
+
     return 0;
 }
 
@@ -61,13 +76,7 @@
 void ec_device_clear(ec_device_t *device /**< EtherCAT-Gerät */)
 {
     if (device->open) ec_device_close(device);
-
-    device->dev = NULL;
-
-    if (device->tx_skb) {
-        dev_kfree_skb(device->tx_skb);
-        device->tx_skb = NULL;
-    }
+    if (device->tx_skb) dev_kfree_skb(device->tx_skb);
 }
 
 /*****************************************************************************/
@@ -100,8 +109,6 @@
     // Device could have received frames before
     for (i = 0; i < 4; i++) ec_device_call_isr(device);
 
-    // Reset old device state
-    device->state = EC_DEVICE_STATE_READY;
     device->link_state = 0;
 
     if (device->dev->open(device->dev) == 0) device->open = 1;
@@ -127,10 +134,10 @@
 
     if (!device->open) {
         EC_WARN("Device already closed!\n");
-    }
-    else {
-        if (device->dev->stop(device->dev) == 0) device->open = 0;
-    }
+        return 0;
+    }
+
+    if (device->dev->stop(device->dev) == 0) device->open = 0;
 
     return !device->open ? 0 : -1;
 }
@@ -138,18 +145,14 @@
 /*****************************************************************************/
 
 /**
-   Bereitet den geräteinternen Socket-Buffer auf den Versand vor.
+   Liefert einen Zeiger auf den Sende-Speicher.
 
    \return Zeiger auf den Speicher, in den die Frame-Daten sollen.
 */
 
-uint8_t *ec_device_prepare(ec_device_t *device /**< EtherCAT-Gerät */)
-{
-    skb_trim(device->tx_skb, 0); // Auf Länge 0 abschneiden
-    skb_reserve(device->tx_skb, ETH_HLEN); // Reserve für Ethernet-II-Header
-
-    // Vorerst Speicher für maximal langen Frame reservieren
-    return skb_put(device->tx_skb, EC_MAX_FRAME_SIZE);
+uint8_t *ec_device_tx_data(ec_device_t *device /**< EtherCAT-Gerät */)
+{
+    return device->tx_skb->data + ETH_HLEN;
 }
 
 /*****************************************************************************/
@@ -163,65 +166,27 @@
 */
 
 void ec_device_send(ec_device_t *device, /**< EtherCAT-Gerät */
-                    unsigned int length /**< Länge der zu sendenden Daten */
+                    size_t size /**< Größe der zu sendenden Daten */
                     )
 {
-    struct ethhdr *eth;
-
     if (unlikely(!device->link_state)) // Link down
         return;
 
     // Framegröße auf (jetzt bekannte) Länge abschneiden
-    skb_trim(device->tx_skb, length);
-
-    // Ethernet-II-Header hinzufuegen
-    eth = (struct ethhdr *) skb_push(device->tx_skb, ETH_HLEN);
-    eth->h_proto = htons(0x88A4);
-    memcpy(eth->h_source, device->dev->dev_addr, device->dev->addr_len);
-    memset(eth->h_dest, 0xFF, device->dev->addr_len);
-
-    device->state = EC_DEVICE_STATE_SENT;
-    device->rx_data_size = 0;
+    device->tx_skb->len = ETH_HLEN + size;
 
     if (unlikely(device->master->debug_level > 1)) {
-        EC_DBG("Sending frame:\n");
-        ec_data_print(device->tx_skb->data + ETH_HLEN, device->tx_skb->len);
+        EC_DBG("sending frame:\n");
+        ec_data_print(device->tx_skb->data + ETH_HLEN, size);
     }
 
     // Senden einleiten
-    rdtscl(device->tx_time); // Get CPU cycles
     device->dev->hard_start_xmit(device->tx_skb, device->dev);
 }
 
 /*****************************************************************************/
 
 /**
-   Gibt die Anzahl der empfangenen Bytes zurück.
-
-   \return Empfangene Bytes, oder 0, wenn kein Frame empfangen wurde.
-*/
-
-unsigned int ec_device_received(const ec_device_t *device)
-{
-    return device->rx_data_size;
-}
-
-/*****************************************************************************/
-
-/**
-   Gibt die empfangenen Daten zurück.
-
-   \return Zeiger auf empfangene Daten.
-*/
-
-uint8_t *ec_device_data(ec_device_t *device)
-{
-    return device->rx_data;
-}
-
-/*****************************************************************************/
-
-/**
    Ruft die Interrupt-Routine der Netzwerkkarte auf.
 */
 
@@ -233,49 +198,6 @@
 /*****************************************************************************/
 
 /**
-   Gibt alle Informationen über das Device-Objekt aus.
-*/
-
-void ec_device_print(ec_device_t *device /**< EtherCAT-Gerät */)
-{
-    EC_DBG("---EtherCAT device information begin---\n");
-
-    if (device) {
-        EC_DBG("Assigned net_device: %X\n", (u32) device->dev);
-        EC_DBG("Transmit socket buffer: %X\n", (u32) device->tx_skb);
-        EC_DBG("Time of last transmission: %u\n", (u32) device->tx_time);
-        EC_DBG("Time of last receive: %u\n", (u32) device->rx_time);
-        EC_DBG("Actual device state: %i\n", (u8) device->state);
-        EC_DBG("Receive buffer: %X\n", (u32) device->rx_data);
-        EC_DBG("Receive buffer fill state: %u/%u\n",
-               (u32) device->rx_data_size, EC_MAX_FRAME_SIZE);
-    }
-    else {
-        EC_DBG("Device is NULL!\n");
-    }
-
-    EC_DBG("---EtherCAT device information end---\n");
-}
-
-/*****************************************************************************/
-
-/**
-   Gibt das letzte Rahmenpaar aus.
-*/
-
-void ec_device_debug(const ec_device_t *device /**< EtherCAT-Gerät */)
-{
-    EC_DBG(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
-    ec_data_print(device->tx_skb->data + ETH_HLEN, device->tx_skb->len);
-    EC_DBG("--------------------------------------\n");
-    ec_data_print_diff(device->tx_skb->data + ETH_HLEN, device->rx_data,
-                       device->rx_data_size);
-    EC_DBG("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
-}
-
-/*****************************************************************************/
-
-/**
    Gibt Frame-Inhalte zwecks Debugging aus.
 */
 
@@ -328,19 +250,6 @@
  *****************************************************************************/
 
 /**
-   Setzt den Zustand des EtherCAT-Gerätes.
-*/
-
-void EtherCAT_dev_state(ec_device_t *device,  /**< EtherCAT-Gerät */
-                        ec_device_state_t state /**< Neuer Zustand */
-                        )
-{
-    device->state = state;
-}
-
-/*****************************************************************************/
-
-/**
    Prüft, ob das Net-Device \a dev zum registrierten EtherCAT-Gerät gehört.
 
    \return 0 wenn nein, nicht-null wenn ja.
@@ -366,16 +275,12 @@
                           size_t size /**< Größe der empfangenen Daten */
                           )
 {
-    // Copy received data to ethercat-device buffer
-    memcpy(device->rx_data, data, size);
-    device->rx_data_size = size;
-    device->state = EC_DEVICE_STATE_RECEIVED;
-
     if (unlikely(device->master->debug_level > 1)) {
         EC_DBG("Received frame:\n");
-        ec_data_print_diff(device->tx_skb->data + ETH_HLEN, device->rx_data,
-                           device->rx_data_size);
-    }
+        ec_data_print_diff(device->tx_skb->data + ETH_HLEN, data, size);
+    }
+
+    ec_master_receive(device->master, data, size);
 }
 
 /*****************************************************************************/
@@ -397,7 +302,6 @@
 /*****************************************************************************/
 
 EXPORT_SYMBOL(EtherCAT_dev_is_ec);
-EXPORT_SYMBOL(EtherCAT_dev_state);
 EXPORT_SYMBOL(EtherCAT_dev_receive);
 EXPORT_SYMBOL(EtherCAT_dev_link_state);
 
--- a/master/device.h	Thu Mar 02 13:08:07 2006 +0000
+++ b/master/device.h	Mon Mar 06 15:12:34 2006 +0000
@@ -17,6 +17,8 @@
 #include "../include/EtherCAT_dev.h"
 #include "globals.h"
 
+typedef irqreturn_t (*ec_isr_t)(int, void *, struct pt_regs *);
+
 /*****************************************************************************/
 
 /**
@@ -33,36 +35,24 @@
     struct net_device *dev; /**< Zeiger auf das reservierte net_device */
     uint8_t open; /**< Das net_device ist geoeffnet. */
     struct sk_buff *tx_skb; /**< Zeiger auf Transmit-Socketbuffer */
-    unsigned long tx_time;  /**< Zeit des letzten Sendens */
-    unsigned long rx_time;  /**< Zeit des letzten Empfangs */
-    ec_device_state_t state; /**< Zustand des Gerätes */
-    uint8_t rx_data[EC_MAX_FRAME_SIZE]; /**< Speicher für empfangene Rahmen */
-    size_t rx_data_size; /**< Länge des empfangenen Rahmens */
-    irqreturn_t (*isr)(int, void *, struct pt_regs *); /**< Adresse der ISR */
+    ec_isr_t isr; /**< Adresse der ISR */
     struct module *module; /**< Zeiger auf das Modul, das das Gerät zur
                               Verfügung stellt. */
-    uint8_t error_reported; /**< Zeigt an, ob ein Fehler im zyklischen Code
-                               bereits gemeldet wurde. */
     uint8_t link_state; /**< Verbindungszustand */
 };
 
 /*****************************************************************************/
 
-int ec_device_init(ec_device_t *, ec_master_t *);
+int ec_device_init(ec_device_t *, ec_master_t *, struct net_device *,
+                   ec_isr_t, struct module *);
 void ec_device_clear(ec_device_t *);
 
 int ec_device_open(ec_device_t *);
 int ec_device_close(ec_device_t *);
 
 void ec_device_call_isr(ec_device_t *);
-uint8_t *ec_device_prepare(ec_device_t *);
+uint8_t *ec_device_tx_data(ec_device_t *);
 void ec_device_send(ec_device_t *, size_t);
-unsigned int ec_device_received(const ec_device_t *);
-uint8_t *ec_device_data(ec_device_t *);
-
-void ec_device_debug(const ec_device_t *);
-void ec_data_print(const uint8_t *, size_t);
-void ec_data_print_diff(const uint8_t *, const uint8_t *, size_t);
 
 /*****************************************************************************/
 
--- a/master/domain.c	Thu Mar 02 13:08:07 2006 +0000
+++ b/master/domain.c	Mon Mar 06 15:12:34 2006 +0000
@@ -12,6 +12,8 @@
 #include "domain.h"
 #include "master.h"
 
+void ec_domain_clear_field_regs(ec_domain_t *);
+
 /*****************************************************************************/
 
 /**
@@ -30,6 +32,8 @@
 
     domain->data = NULL;
     domain->data_size = 0;
+    domain->commands = NULL;
+    domain->command_count = 0;
     domain->base_address = 0;
     domain->response_count = 0xFFFFFFFF;
 
@@ -44,17 +48,10 @@
 
 void ec_domain_clear(ec_domain_t *domain /**< Domäne */)
 {
-    ec_field_reg_t *field_reg, *next;
-
-    if (domain->data) {
-        kfree(domain->data);
-        domain->data = NULL;
-    }
-
-    // Liste der registrierten Datenfelder löschen
-    list_for_each_entry_safe(field_reg, next, &domain->field_regs, list) {
-        kfree(field_reg);
-    }
+    if (domain->data) kfree(domain->data);
+    if (domain->commands) kfree(domain->commands);
+
+    ec_domain_clear_field_regs(domain);
 }
 
 /*****************************************************************************/
@@ -99,6 +96,22 @@
 /*****************************************************************************/
 
 /**
+   Gibt die Liste der registrierten Datenfelder frei.
+*/
+
+void ec_domain_clear_field_regs(ec_domain_t *domain)
+{
+    ec_field_reg_t *field_reg, *next;
+
+    list_for_each_entry_safe(field_reg, next, &domain->field_regs, list) {
+        list_del(&field_reg->list);
+        kfree(field_reg);
+    }
+}
+
+/*****************************************************************************/
+
+/**
    Erzeugt eine Domäne.
 
    Reserviert den Speicher einer Domäne, berechnet die logischen Adressen der
@@ -111,7 +124,7 @@
                     uint32_t base_address /**< Logische Basisadresse */
                     )
 {
-    ec_field_reg_t *field_reg, *next;
+    ec_field_reg_t *field_reg;
     ec_slave_t *slave;
     ec_fmmu_t *fmmu;
     unsigned int i, j, found, data_offset;
@@ -139,43 +152,52 @@
 
     if (!domain->data_size) {
         EC_WARN("Domain 0x%08X contains no data!\n", (u32) domain);
-    }
-    else {
-        // Prozessdaten allozieren
-        if (!(domain->data = kmalloc(domain->data_size, GFP_KERNEL))) {
-            EC_ERR("Failed to allocate domain data!\n");
+        ec_domain_clear_field_regs(domain);
+        return 0;
+    }
+
+    // Prozessdaten allozieren
+    if (!(domain->data = kmalloc(domain->data_size, GFP_KERNEL))) {
+        EC_ERR("Failed to allocate domain data!\n");
+        return -1;
+    }
+
+    // Prozessdaten mit Nullen vorbelegen
+    memset(domain->data, 0x00, domain->data_size);
+
+    // Alle Prozessdatenzeiger setzen
+    list_for_each_entry(field_reg, &domain->field_regs, list) {
+        found = 0;
+        for (i = 0; i < field_reg->slave->fmmu_count; i++) {
+            fmmu = &field_reg->slave->fmmus[i];
+            if (fmmu->domain == domain && fmmu->sync == field_reg->sync) {
+                data_offset = fmmu->logical_start_address - base_address
+                    + field_reg->field_offset;
+                *field_reg->data_ptr = domain->data + data_offset;
+                found = 1;
+                break;
+            }
+        }
+
+        if (!found) { // Sollte nie passieren
+            EC_ERR("FMMU not found. Please report!\n");
             return -1;
         }
-
-        // Prozessdaten mit Nullen vorbelegen
-        memset(domain->data, 0x00, domain->data_size);
-
-        // Alle Prozessdatenzeiger setzen
-        list_for_each_entry(field_reg, &domain->field_regs, list) {
-            found = 0;
-            for (i = 0; i < field_reg->slave->fmmu_count; i++) {
-                fmmu = &field_reg->slave->fmmus[i];
-                if (fmmu->domain == domain && fmmu->sync == field_reg->sync) {
-                    data_offset = fmmu->logical_start_address - base_address
-                        + field_reg->field_offset;
-                    *field_reg->data_ptr = domain->data + data_offset;
-                    found = 1;
-                    break;
-                }
-            }
-
-            if (!found) { // Sollte nie passieren
-                EC_ERR("FMMU not found. Please report!\n");
-                return -1;
-            }
-        }
-    }
-
-    // Registrierungsliste wird jetzt nicht mehr gebraucht.
-    list_for_each_entry_safe(field_reg, next, &domain->field_regs, list) {
-        kfree(field_reg);
-    }
-    INIT_LIST_HEAD(&domain->field_regs); // wichtig!
+    }
+
+    // Kommando-Array erzeugen
+    domain->command_count = domain->data_size / EC_MAX_DATA_SIZE + 1;
+    if (!(domain->commands = (ec_command_t *) kmalloc(sizeof(ec_command_t)
+                                                      * domain->command_count,
+                                                      GFP_KERNEL))) {
+        EC_ERR("Failed to allocate domain command array!\n");
+        return -1;
+    }
+
+    EC_INFO("Domain %X - Allocated %i bytes in %i command(s)\n",
+            (u32) domain, domain->data_size, domain->command_count);
+
+    ec_domain_clear_field_regs(domain);
 
     return 0;
 }
@@ -192,8 +214,8 @@
 {
     if (count != domain->response_count) {
         domain->response_count = count;
-        EC_INFO("Domain %08X state change - %i slaves responding.\n",
-                (u32) domain, count);
+        EC_INFO("Domain %08X state change - %i slave%s responding.\n",
+                (u32) domain, count, count == 1 ? "" : "s");
     }
 }
 
@@ -209,17 +231,28 @@
    \return Zeiger auf den Slave bei Erfolg, sonst NULL
 */
 
-ec_slave_t *EtherCAT_rt_register_slave_field(
-    ec_domain_t *domain, /**< Domäne */
-    const char *address, /**< ASCII-Addresse des Slaves, siehe ec_address() */
-    const char *vendor_name, /**< Herstellername */
-    const char *product_name, /**< Produktname */
-    void **data_ptr, /**< Adresse des Zeigers auf die Prozessdaten */
-    ec_field_type_t field_type, /**< Typ des Datenfeldes */
-    unsigned int field_index, /**< Gibt an, ab welchem Feld mit Typ
-                                 \a field_type gezählt werden soll. */
-    unsigned int field_count /**< Anzahl Felder des selben Typs */
-    )
+ec_slave_t *EtherCAT_rt_register_slave_field(ec_domain_t *domain,
+                                             /**< Domäne */
+                                             const char *address,
+                                             /**< ASCII-Addresse des Slaves,
+                                                siehe ec_master_slave_address()
+                                             */
+                                             const char *vendor_name,
+                                             /**< Herstellername */
+                                             const char *product_name,
+                                             /**< Produktname */
+                                             void **data_ptr,
+                                             /**< Adresse des Zeigers auf die
+                                                Prozessdaten */
+                                             ec_field_type_t field_type,
+                                             /**< Typ des Datenfeldes */
+                                             unsigned int field_index,
+                                             /**< Gibt an, ab welchem Feld mit
+                                                Typ \a field_type gezählt
+                                                werden soll. */
+                                             unsigned int field_count
+                                             /**< Anzahl Felder selben Typs */
+                                             )
 {
     ec_slave_t *slave;
     const ec_slave_type_t *type;
@@ -237,7 +270,7 @@
     master = domain->master;
 
     // Adresse übersetzen
-    if ((slave = ec_address(master, address)) == NULL) return NULL;
+    if (!(slave = ec_master_slave_address(master, address))) return NULL;
 
     if (!(type = slave->type)) {
         EC_ERR("Slave \"%s\" (position %i) has unknown type!\n", address,
@@ -280,96 +313,96 @@
 /*****************************************************************************/
 
 /**
-   Sendet und empfängt Prozessdaten der angegebenen Domäne.
+   Registriert eine ganze Liste von Datenfeldern innerhalb einer Domäne.
+
+   Achtung: Die Liste muss mit einer NULL-Struktur ({}) abgeschlossen sein!
 
    \return 0 bei Erfolg, sonst < 0
 */
 
-int EtherCAT_rt_domain_xio(ec_domain_t *domain /**< Domäne */)
-{
-    unsigned int offset, size, working_counter_sum;
-    unsigned long start_ticks, end_ticks, timeout_ticks;
-    ec_master_t *master;
-    ec_frame_t *frame;
-
-    master = domain->master;
-    frame = &domain->frame;
-    working_counter_sum = 0;
-
-    ec_cyclic_output(master);
-
-    if (unlikely(!master->device.link_state)) {
-        ec_domain_response_count(domain, working_counter_sum);
-        ec_device_call_isr(&master->device);
-        return -1;
-    }
-
-    rdtscl(start_ticks); // Sendezeit nehmen
-    timeout_ticks = domain->timeout_us * cpu_khz / 1000;
+int EtherCAT_rt_register_domain_fields(ec_domain_t *domain,
+                                       /**< Domäne */
+                                       ec_field_init_t *fields
+                                       /**< Array mit Datenfeldern */
+                                       )
+{
+    ec_field_init_t *field;
+
+    for (field = fields; field->data; field++) {
+        if (!EtherCAT_rt_register_slave_field(domain, field->address,
+                                              field->vendor, field->product,
+                                              field->data, field->field_type,
+                                              field->field_index,
+                                              field->field_count)) {
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+/*****************************************************************************/
+
+/**
+   Setzt Prozessdaten-Kommandos in die Warteschlange des Masters.
+*/
+
+void EtherCAT_rt_domain_queue(ec_domain_t *domain /**< Domäne */)
+{
+    unsigned int offset, i;
+    size_t size;
 
     offset = 0;
-    while (offset < domain->data_size)
-    {
+    for (i = 0; i < domain->command_count; i++) {
         size = domain->data_size - offset;
         if (size > EC_MAX_DATA_SIZE) size = EC_MAX_DATA_SIZE;
-
-        ec_frame_init_lrw(frame, master, domain->base_address + offset, size,
-                          domain->data + offset);
-
-        if (unlikely(ec_frame_send(frame) < 0)) {
-            master->device.state = EC_DEVICE_STATE_READY;
-            master->frames_lost++;
-            ec_cyclic_output(master);
-            ec_domain_response_count(domain, working_counter_sum);
-            return -1;
-        }
-
-        // Warten
-        do {
-            ec_device_call_isr(&master->device);
-            rdtscl(end_ticks); // Empfangszeit nehmen
-        }
-        while (unlikely(master->device.state == EC_DEVICE_STATE_SENT
-                        && end_ticks - start_ticks < timeout_ticks));
-
-        master->bus_time = (end_ticks - start_ticks) * 1000 / cpu_khz;
-
-        if (unlikely(end_ticks - start_ticks >= timeout_ticks)) {
-            if (master->device.state == EC_DEVICE_STATE_RECEIVED) {
-                master->frames_delayed++;
-                ec_cyclic_output(master);
-            }
-            else {
-                master->device.state = EC_DEVICE_STATE_READY;
-                master->frames_lost++;
-                ec_cyclic_output(master);
-                ec_domain_response_count(domain, working_counter_sum);
-                return -1;
-            }
-        }
-
-        if (unlikely(ec_frame_receive(frame) < 0)) {
-            ec_domain_response_count(domain, working_counter_sum);
-            return -1;
-        }
-
-        working_counter_sum += frame->working_counter;
-
-        // Daten vom Rahmen in den Prozessdatenspeicher kopieren
-        memcpy(domain->data + offset, frame->data, size);
-
+        ec_command_init_lrw(domain->commands + i,
+                            domain->base_address + offset, size,
+                            domain->data + offset);
+        ec_master_queue_command(domain->master, domain->commands + i);
         offset += size;
     }
+}
+
+/*****************************************************************************/
+
+/**
+   Verarbeitet empfangene Prozessdaten.
+*/
+
+void EtherCAT_rt_domain_process(ec_domain_t *domain /**< Domäne */)
+{
+    unsigned int offset, working_counter_sum, i;
+    ec_command_t *command;
+    size_t size;
+
+    working_counter_sum = 0;
+
+    offset = 0;
+    for (i = 0; i < domain->command_count; i++) {
+        command = domain->commands + i;
+        size = domain->data_size - offset;
+        if (size > EC_MAX_DATA_SIZE) size = EC_MAX_DATA_SIZE;
+        if (command->state == EC_CMD_RECEIVED) {
+            // Daten vom Kommando- in den Prozessdatenspeicher kopieren
+            memcpy(domain->data + offset, command->data, size);
+            working_counter_sum += command->working_counter;
+        }
+        else if (unlikely(domain->master->debug_level)) {
+            EC_DBG("process data command not received!\n");
+        }
+        offset += size;
+    }
 
     ec_domain_response_count(domain, working_counter_sum);
-
-    return 0;
 }
 
 /*****************************************************************************/
 
 EXPORT_SYMBOL(EtherCAT_rt_register_slave_field);
-EXPORT_SYMBOL(EtherCAT_rt_domain_xio);
+EXPORT_SYMBOL(EtherCAT_rt_register_domain_fields);
+EXPORT_SYMBOL(EtherCAT_rt_domain_queue);
+EXPORT_SYMBOL(EtherCAT_rt_domain_process);
 
 /*****************************************************************************/
 
--- a/master/domain.h	Thu Mar 02 13:08:07 2006 +0000
+++ b/master/domain.h	Mon Mar 06 15:12:34 2006 +0000
@@ -15,7 +15,7 @@
 
 #include "globals.h"
 #include "slave.h"
-#include "frame.h"
+#include "command.h"
 
 /*****************************************************************************/
 
@@ -46,17 +46,14 @@
 {
     struct list_head list; /**< Listenkopf */
     ec_master_t *master; /**< EtherCAT-Master, zu der die Domäne gehört. */
-
-    unsigned char *data; /**< Prozessdaten */
-    unsigned int data_size; /**< Größe der Prozessdaten */
-
-    ec_frame_t frame; /**< EtherCAT-Frame für die Prozessdaten */
-
+    uint8_t *data; /**< Prozessdaten */
+    size_t data_size; /**< Größe der Prozessdaten */
+    ec_command_t *commands; /**< EtherCAT-Kommandos für die Prozessdaten */
+    unsigned int command_count; /**< Anzahl allozierter Kommandos */
     ec_domain_mode_t mode;
     unsigned int timeout_us; /**< Timeout in Mikrosekunden. */
     unsigned int base_address; /**< Logische Basisaddresse der Domain */
     unsigned int response_count; /**< Anzahl antwortender Slaves */
-
     struct list_head field_regs; /**< Liste der Datenfeldregistrierungen */
 };
 
--- a/master/frame.c	Thu Mar 02 13:08:07 2006 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,463 +0,0 @@
-/******************************************************************************
- *
- *  f r a m e . c
- *
- *  Methoden für einen EtherCAT-Frame.
- *
- *  $Id$
- *
- *****************************************************************************/
-
-#include <linux/slab.h>
-#include <linux/delay.h>
-
-#include "../include/EtherCAT_si.h"
-#include "frame.h"
-#include "master.h"
-
-/*****************************************************************************/
-
-#define EC_FUNC_HEADER \
-    frame->master = master; \
-    frame->index = 0; \
-    frame->working_counter = 0;
-
-#define EC_FUNC_WRITE_FOOTER \
-    frame->data_length = length; \
-    memcpy(frame->data, data, length);
-
-#define EC_FUNC_READ_FOOTER \
-    frame->data_length = length; \
-    memset(frame->data, 0x00, length);
-
-/*****************************************************************************/
-
-/**
-   Initialisiert ein EtherCAT-NPRD-Kommando.
-
-   Node-adressed physical read.
-*/
-
-void ec_frame_init_nprd(ec_frame_t *frame,
-                        /**< EtherCAT-Rahmen */
-                        ec_master_t *master,
-                        /**< EtherCAT-Master */
-                        uint16_t node_address,
-                        /**< Adresse des Knotens (Slaves) */
-                        uint16_t offset,
-                        /**< Physikalische Speicheradresse im Slave */
-                        unsigned int length
-                        /**< Länge der zu lesenden Daten */
-                        )
-{
-    if (unlikely(node_address == 0x0000))
-        EC_WARN("Using node address 0x0000!\n");
-
-    EC_FUNC_HEADER;
-
-    frame->type = ec_frame_type_nprd;
-    frame->address.physical.slave = node_address;
-    frame->address.physical.mem = offset;
-
-    EC_FUNC_READ_FOOTER;
-}
-
-/*****************************************************************************/
-
-/**
-   Initialisiert ein EtherCAT-NPWR-Kommando.
-
-   Node-adressed physical write.
-*/
-
-void ec_frame_init_npwr(ec_frame_t *frame,
-                        /**< EtherCAT-Rahmen */
-                        ec_master_t *master,
-                        /**< EtherCAT-Master */
-                        uint16_t node_address,
-                        /**< Adresse des Knotens (Slaves) */
-                        uint16_t offset,
-                        /**< Physikalische Speicheradresse im Slave */
-                        unsigned int length,
-                        /**< Länge der zu schreibenden Daten */
-                        const uint8_t *data
-                        /**< Zeiger auf Speicher mit zu schreibenden Daten */
-                        )
-{
-    if (unlikely(node_address == 0x0000))
-        EC_WARN("Using node address 0x0000!\n");
-
-    EC_FUNC_HEADER;
-
-    frame->type = ec_frame_type_npwr;
-    frame->address.physical.slave = node_address;
-    frame->address.physical.mem = offset;
-
-    EC_FUNC_WRITE_FOOTER;
-}
-
-/*****************************************************************************/
-
-/**
-   Initialisiert ein EtherCAT-APRD-Kommando.
-
-   Autoincrement physical read.
-*/
-
-void ec_frame_init_aprd(ec_frame_t *frame,
-                        /**< EtherCAT-Rahmen */
-                        ec_master_t *master,
-                        /**< EtherCAT-Master */
-                        uint16_t ring_position,
-                        /**< Position des Slaves im Bus */
-                        uint16_t offset,
-                        /**< Physikalische Speicheradresse im Slave */
-                        unsigned int length
-                        /**< Länge der zu lesenden Daten */
-                        )
-{
-    EC_FUNC_HEADER;
-
-    frame->type = ec_frame_type_aprd;
-    frame->address.physical.slave = (int16_t) ring_position * (-1);
-    frame->address.physical.mem = offset;
-
-    EC_FUNC_READ_FOOTER;
-}
-
-/*****************************************************************************/
-
-/**
-   Initialisiert ein EtherCAT-APWR-Kommando.
-
-   Autoincrement physical write.
-*/
-
-void ec_frame_init_apwr(ec_frame_t *frame,
-                        /**< EtherCAT-Rahmen */
-                        ec_master_t *master,
-                        /**< EtherCAT-Master */
-                        uint16_t ring_position,
-                        /**< Position des Slaves im Bus */
-                        uint16_t offset,
-                        /**< Physikalische Speicheradresse im Slave */
-                        unsigned int length,
-                        /**< Länge der zu schreibenden Daten */
-                        const uint8_t *data
-                        /**< Zeiger auf Speicher mit zu schreibenden Daten */
-                        )
-{
-    EC_FUNC_HEADER;
-
-    frame->type = ec_frame_type_apwr;
-    frame->address.physical.slave = (int16_t) ring_position * (-1);
-    frame->address.physical.mem = offset;
-
-    EC_FUNC_WRITE_FOOTER;
-}
-
-/*****************************************************************************/
-
-/**
-   Initialisiert ein EtherCAT-BRD-Kommando.
-
-   Broadcast read.
-*/
-
-void ec_frame_init_brd(ec_frame_t *frame,
-                       /**< EtherCAT-Rahmen */
-                       ec_master_t *master,
-                       /**< EtherCAT-Master */
-                       uint16_t offset,
-                       /**< Physikalische Speicheradresse im Slave */
-                       unsigned int length
-                       /**< Länge der zu lesenden Daten */
-                       )
-{
-    EC_FUNC_HEADER;
-
-    frame->type = ec_frame_type_brd;
-    frame->address.physical.slave = 0x0000;
-    frame->address.physical.mem = offset;
-
-    EC_FUNC_READ_FOOTER;
-}
-
-/*****************************************************************************/
-
-/**
-   Initialisiert ein EtherCAT-BWR-Kommando.
-
-   Broadcast write.
-*/
-
-void ec_frame_init_bwr(ec_frame_t *frame,
-                       /**< EtherCAT-Rahmen */
-                       ec_master_t *master,
-                       /**< EtherCAT-Master */
-                       uint16_t offset,
-                       /**< Physikalische Speicheradresse im Slave */
-                       unsigned int length,
-                       /**< Länge der zu schreibenden Daten */
-                       const uint8_t *data
-                       /**< Zeiger auf Speicher mit zu schreibenden Daten */
-                       )
-{
-    EC_FUNC_HEADER;
-
-    frame->type = ec_frame_type_bwr;
-    frame->address.physical.slave = 0x0000;
-    frame->address.physical.mem = offset;
-
-    EC_FUNC_WRITE_FOOTER;
-}
-
-/*****************************************************************************/
-
-/**
-   Initialisiert ein EtherCAT-LRW-Kommando.
-
-   Logical read write.
-*/
-
-void ec_frame_init_lrw(ec_frame_t *frame,
-                       /**< EtherCAT-Rahmen */
-                       ec_master_t *master,
-                       /**< EtherCAT-Master */
-                       uint32_t offset,
-                       /**< Logische Startadresse */
-                       unsigned int length,
-                       /**< Länge der zu lesenden/schreibenden Daten */
-                       uint8_t *data
-                       /**< Zeiger auf die Daten */
-                       )
-{
-    EC_FUNC_HEADER;
-
-    frame->type = ec_frame_type_lrw;
-    frame->address.logical = offset;
-
-    EC_FUNC_WRITE_FOOTER;
-}
-
-/*****************************************************************************/
-
-/**
-   Sendet einen einzelnen EtherCAT-Rahmen.
-
-   \return 0 bei Erfolg, sonst < 0
-*/
-
-int ec_frame_send(ec_frame_t *frame /**< Rahmen zum Senden */)
-{
-    unsigned int command_size, frame_size, i;
-    uint8_t *data;
-
-    if (unlikely(!frame->master->device.link_state))
-        return -1;
-
-    if (unlikely(frame->master->debug_level > 0)) {
-        EC_DBG("ec_frame_send\n");
-    }
-
-    command_size = frame->data_length + EC_COMMAND_HEADER_SIZE
-        + EC_COMMAND_FOOTER_SIZE;
-    frame_size = command_size + EC_FRAME_HEADER_SIZE;
-
-    if (unlikely(frame_size > EC_MAX_FRAME_SIZE)) {
-        EC_ERR("Frame too long (%i)!\n", frame_size);
-        return -1;
-    }
-
-    if (frame_size < EC_MIN_FRAME_SIZE) frame_size = EC_MIN_FRAME_SIZE;
-
-    if (unlikely(frame->master->debug_level > 0)) {
-        EC_DBG("Frame length: %i\n", frame_size);
-    }
-
-    frame->index = frame->master->command_index;
-    frame->master->command_index = (frame->master->command_index + 1) % 0x0100;
-
-    if (unlikely(frame->master->debug_level > 0)) {
-        EC_DBG("Sending command index 0x%X\n", frame->index);
-    }
-
-    // Zeiger auf Socket-Buffer holen
-    data = ec_device_prepare(&frame->master->device);
-
-    // EtherCAT frame header
-    EC_WRITE_U16(data, (command_size & 0x7FF) | 0x1000);
-    data += EC_FRAME_HEADER_SIZE;
-
-    // EtherCAT command header
-    EC_WRITE_U8 (data,     frame->type);
-    EC_WRITE_U8 (data + 1, frame->index);
-    EC_WRITE_U32(data + 2, frame->address.logical);
-    EC_WRITE_U16(data + 6, frame->data_length & 0x7FF);
-    EC_WRITE_U16(data + 8, 0x0000);
-    data += EC_COMMAND_HEADER_SIZE;
-
-    // EtherCAT command data
-    memcpy(data, frame->data, frame->data_length);
-    data += frame->data_length;
-
-    // EtherCAT command footer
-    EC_WRITE_U16(data, frame->working_counter);
-    data += EC_COMMAND_FOOTER_SIZE;
-
-    // Pad with zeros
-    for (i = EC_FRAME_HEADER_SIZE + EC_COMMAND_HEADER_SIZE
-             + frame->data_length + EC_COMMAND_FOOTER_SIZE;
-         i < EC_MIN_FRAME_SIZE; i++)
-        EC_WRITE_U8(data++, 0x00);
-
-    // Send frame
-    ec_device_send(&frame->master->device, frame_size);
-
-    return 0;
-}
-
-/*****************************************************************************/
-
-/**
-   Wertet empfangene Daten zu einem Rahmen aus.
-
-   \return 0 bei Erfolg, sonst < 0
-*/
-
-int ec_frame_receive(ec_frame_t *frame /**< Gesendeter Rahmen */)
-{
-    unsigned int received_length, frame_length, data_length;
-    uint8_t *data;
-    uint8_t command_type, command_index;
-    ec_device_t *device;
-
-    device = &frame->master->device;
-
-    if (!(received_length = ec_device_received(device))) return -1;
-
-    device->state = EC_DEVICE_STATE_READY;
-
-    if (unlikely(received_length < EC_FRAME_HEADER_SIZE)) {
-        EC_ERR("Received frame with incomplete EtherCAT frame header!\n");
-        ec_device_debug(device);
-        return -1;
-    }
-
-    data = ec_device_data(device);
-
-    // Länge des gesamten Frames prüfen
-    frame_length = EC_READ_U16(data) & 0x07FF;
-    data += EC_FRAME_HEADER_SIZE;
-
-    if (unlikely(frame_length > received_length)) {
-        EC_ERR("Received corrupted frame (length does not match)!\n");
-        ec_device_debug(device);
-        return -1;
-    }
-
-    // Command header
-    command_type =  EC_READ_U8(data);
-    command_index = EC_READ_U8(data + 1);
-    data_length =   EC_READ_U16(data + 6) & 0x07FF;
-    data += EC_COMMAND_HEADER_SIZE;
-
-    if (unlikely(EC_FRAME_HEADER_SIZE + EC_COMMAND_HEADER_SIZE
-                 + data_length + EC_COMMAND_FOOTER_SIZE > received_length)) {
-        EC_ERR("Received frame with incomplete command data!\n");
-        ec_device_debug(device);
-        return -1;
-    }
-
-    if (unlikely(frame->type != command_type
-                 || frame->index != command_index
-                 || frame->data_length != data_length))
-    {
-        EC_WARN("WARNING - Send/Receive anomaly!\n");
-        ec_device_debug(device);
-        ec_device_call_isr(device); // Empfangenes "vergessen"
-        return -1;
-    }
-
-    // Empfangene Daten in Kommandodatenspeicher kopieren
-    memcpy(frame->data, data, data_length);
-    data += data_length;
-
-    // Working-Counter setzen
-    frame->working_counter = EC_READ_U16(data);
-
-    return 0;
-}
-
-/*****************************************************************************/
-
-/**
-   Sendet einen einzeln Rahmen und wartet auf dessen Empfang.
-
-   Wenn der Working-Counter nicht gesetzt wurde, wird der Rahmen
-   nochmals gesendet.
-
-   \todo Das ist noch nicht schön, da hier zwei Protokollschichten
-   vermischt werden.
-
-   \return 0 bei Erfolg, sonst < 0
-*/
-
-int ec_frame_send_receive(ec_frame_t *frame
-                          /**< Rahmen zum Senden/Empfangen */
-                          )
-{
-    unsigned int timeout_tries_left, response_tries_left;
-    unsigned int tries;
-
-    tries = 0;
-    response_tries_left = 10;
-    do
-    {
-        tries++;
-        if (unlikely(ec_frame_send(frame) < 0)) {
-            EC_ERR("Frame sending failed!\n");
-            return -1;
-        }
-
-        timeout_tries_left = 20;
-        do
-        {
-            udelay(1);
-            ec_device_call_isr(&frame->master->device);
-            timeout_tries_left--;
-        }
-        while (unlikely(!ec_device_received(&frame->master->device)
-                        && timeout_tries_left));
-
-        if (unlikely(!timeout_tries_left)) {
-            EC_ERR("Frame timeout!\n");
-            return -1;
-        }
-
-        if (unlikely(ec_frame_receive(frame) < 0)) {
-            EC_ERR("Frame receiving failed!\n");
-            return -1;
-        }
-
-        response_tries_left--;
-    }
-    while (unlikely(!frame->working_counter && response_tries_left));
-
-    if (unlikely(!response_tries_left)) {
-        EC_ERR("No response!");
-        return -1;
-    }
-
-    if (tries > 1) EC_WARN("%i tries necessary...\n", tries);
-
-    return 0;
-}
-
-/*****************************************************************************/
-
-/* Emacs-Konfiguration
-;;; Local Variables: ***
-;;; c-basic-offset:4 ***
-;;; End: ***
-*/
--- a/master/frame.h	Thu Mar 02 13:08:07 2006 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,111 +0,0 @@
-/******************************************************************************
- *
- *  f r a m e . h
- *
- *  Struktur für einen EtherCAT-Rahmen.
- *
- *  $Id$
- *
- *****************************************************************************/
-
-#ifndef _EC_FRAME_H_
-#define _EC_FRAME_H_
-
-#include "globals.h"
-#include "../include/EtherCAT_rt.h"
-
-/*****************************************************************************/
-
-/**
-   EtherCAT-Rahmen-Typ
-*/
-
-typedef enum
-{
-  ec_frame_type_none = 0x00, /**< Dummy */
-  ec_frame_type_aprd = 0x01, /**< Auto-increment physical read */
-  ec_frame_type_apwr = 0x02, /**< Auto-increment physical write */
-  ec_frame_type_nprd = 0x04, /**< Node-addressed physical read */
-  ec_frame_type_npwr = 0x05, /**< Node-addressed physical write */
-  ec_frame_type_brd  = 0x07, /**< Broadcast read */
-  ec_frame_type_bwr  = 0x08, /**< Broadcast write */
-  ec_frame_type_lrw  = 0x0C  /**< Logical read/write */
-}
-ec_frame_type_t;
-
-/*****************************************************************************/
-
-/**
-   EtherCAT-Adresse.
-
-   Im EtherCAT-Rahmen sind 4 Bytes für die Adresse reserviert, die je nach
-   Kommandotyp, eine andere Bedeutung haben können: Bei Autoinkrementbefehlen
-   sind die ersten zwei Bytes die (negative) Autoinkrement-Adresse, bei Knoten-
-   adressierten Befehlen entsprechen sie der Knotenadresse. Das dritte und
-   vierte Byte entspricht in diesen Fällen der physikalischen Speicheradresse
-   auf dem Slave. Bei einer logischen Adressierung entsprechen alle vier Bytes
-   der logischen Adresse.
-*/
-
-typedef union
-{
-  struct
-  {
-      uint16_t slave; /**< Adresse des Slaves (Ringposition oder Knoten) */
-      uint16_t mem; /**< Physikalische Speicheradresse im Slave */
-  }
-  physical; /**< Physikalische Adresse */
-
-  uint32_t logical; /**< Logische Adresse */
-}
-ec_address_t;
-
-/*****************************************************************************/
-
-/**
-   EtherCAT-Frame.
-*/
-
-typedef struct
-{
-    ec_master_t *master; /**< EtherCAT-Master */
-    ec_frame_type_t type; /**< Typ des Frames (APRD, NPWR, etc) */
-    ec_address_t address; /**< Adresse des/der Empfänger */
-    unsigned int data_length; /**< Länge der zu sendenden und/oder empfangenen
-                                 Daten */
-    uint8_t index; /**< Kommando-Index, mit dem der Frame gesendet wurde
-                            (wird vom Master beim Senden gesetzt). */
-    uint16_t working_counter; /**< Working-Counter */
-    uint8_t data[EC_MAX_FRAME_SIZE]; /**< Rahmendaten */
-}
-ec_frame_t;
-
-/*****************************************************************************/
-
-void ec_frame_init_nprd(ec_frame_t *, ec_master_t *, uint16_t, uint16_t,
-                        unsigned int);
-void ec_frame_init_npwr(ec_frame_t *, ec_master_t *, uint16_t, uint16_t,
-                        unsigned int, const unsigned char *);
-void ec_frame_init_aprd(ec_frame_t *, ec_master_t *, uint16_t, uint16_t,
-                        unsigned int);
-void ec_frame_init_apwr(ec_frame_t *, ec_master_t *, uint16_t, uint16_t,
-                        unsigned int, const unsigned char *);
-void ec_frame_init_brd(ec_frame_t *, ec_master_t *, uint16_t, unsigned int);
-void ec_frame_init_bwr(ec_frame_t *, ec_master_t *, uint16_t, unsigned int,
-                       const unsigned char *);
-void ec_frame_init_lrw(ec_frame_t *, ec_master_t *, uint32_t, unsigned int,
-                       unsigned char *);
-
-int ec_frame_send(ec_frame_t *);
-int ec_frame_receive(ec_frame_t *);
-int ec_frame_send_receive(ec_frame_t *);
-
-/*****************************************************************************/
-
-#endif
-
-/* Emacs-Konfiguration
-;;; Local Variables: ***
-;;; c-basic-offset:4 ***
-;;; End: ***
-*/
--- a/master/globals.h	Thu Mar 02 13:08:07 2006 +0000
+++ b/master/globals.h	Mon Mar 06 15:12:34 2006 +0000
@@ -15,7 +15,7 @@
 
 // EtherCAT-Protokoll
 #define EC_MAX_FRAME_SIZE 1500 /**< Maximale Größe eines EtherCAT-Frames ohne
-                                  Ethernet-II-Header und -Prüfsumme*/
+                                  Ethernet-II-Header und -Prüfsumme */
 #define EC_MIN_FRAME_SIZE 46 /** Minimale Größe, s. o. */
 #define EC_FRAME_HEADER_SIZE 2 /**< Größe des EtherCAT-Frame-Headers */
 #define EC_COMMAND_HEADER_SIZE 10 /**< Größe eines EtherCAT-Kommando-Headers */
@@ -43,28 +43,6 @@
 
 /*****************************************************************************/
 
-/**
-   Zustand eines EtherCAT-Slaves
-*/
-
-typedef enum
-{
-    EC_SLAVE_STATE_UNKNOWN = 0x00, /**< Status unbekannt */
-    EC_SLAVE_STATE_INIT = 0x01,    /**< Init-Zustand (Keine Mailbox-
-                                      Kommunikation, Kein I/O) */
-    EC_SLAVE_STATE_PREOP = 0x02,   /**< Pre-Operational (Mailbox-
-                                      Kommunikation, Kein I/O) */
-    EC_SLAVE_STATE_SAVEOP = 0x04,  /**< Save-Operational (Mailbox-
-                                      Kommunikation und Input Update) */
-    EC_SLAVE_STATE_OP = 0x08,      /**< Operational, (Mailbox-
-                                      Kommunikation und Input/Output Update) */
-    EC_ACK = 0x10                  /**< Acknoledge-Bit beim Zustandswechsel
-                                      (dies ist kein eigener Zustand) */
-}
-ec_slave_state_t;
-
-/*****************************************************************************/
-
 #endif
 
 /* Emacs-Konfiguration
--- a/master/master.c	Thu Mar 02 13:08:07 2006 +0000
+++ b/master/master.c	Mon Mar 06 15:12:34 2006 +0000
@@ -21,7 +21,7 @@
 #include "slave.h"
 #include "types.h"
 #include "device.h"
-#include "frame.h"
+#include "command.h"
 
 /*****************************************************************************/
 
@@ -32,16 +32,12 @@
 void ec_master_init(ec_master_t *master /**< EtherCAT-Master */)
 {
     master->slaves = NULL;
-    master->slave_count = 0;
-    master->device_registered = 0;
-    master->command_index = 0x00;
-    master->debug_level = 0;
-    master->bus_time = 0;
-    master->frames_lost = 0;
-    master->frames_delayed = 0;
-    master->t_last_cyclic_output = 0;
-
+    master->device = NULL;
+
+    INIT_LIST_HEAD(&master->commands);
     INIT_LIST_HEAD(&master->domains);
+
+    ec_master_reset(master);
 }
 
 /*****************************************************************************/
@@ -56,7 +52,11 @@
 void ec_master_clear(ec_master_t *master /**< EtherCAT-Master */)
 {
     ec_master_reset(master);
-    ec_device_clear(&master->device);
+
+    if (master->device) {
+        ec_device_clear(master->device);
+        kfree(master->device);
+    }
 }
 
 /*****************************************************************************/
@@ -72,35 +72,11 @@
                      /**< Zeiger auf den zurückzusetzenden Master */
                      )
 {
-    ec_domain_t *domain, *next;
-
-    ec_master_clear_slaves(master);
-
-    // Domain-Liste leeren
-    list_for_each_entry_safe(domain, next, &master->domains, list) {
-        ec_domain_clear(domain);
-        kfree(domain);
-    }
-    INIT_LIST_HEAD(&master->domains);
-
-    master->command_index = 0;
-    master->debug_level = 0;
-    master->bus_time = 0;
-    master->frames_lost = 0;
-    master->frames_delayed = 0;
-    master->t_last_cyclic_output = 0;
-}
-
-/*****************************************************************************/
-
-/**
-   Entfernt alle Slaves.
-*/
-
-void ec_master_clear_slaves(ec_master_t *master /**< EtherCAT-Master */)
-{
     unsigned int i;
-
+    ec_command_t *command, *next_command;
+    ec_domain_t *domain, *next_domain;
+
+    // Alle Slaves entfernen
     if (master->slaves) {
         for (i = 0; i < master->slave_count; i++) {
             ec_slave_clear(master->slaves + i);
@@ -109,6 +85,27 @@
         master->slaves = NULL;
     }
     master->slave_count = 0;
+
+    // Kommando-Warteschlange leeren
+    list_for_each_entry_safe(command, next_command, &master->commands, list) {
+        command->state = EC_CMD_ERROR;
+        list_del_init(&command->list);
+    }
+
+    // Domain-Liste leeren
+    list_for_each_entry_safe(domain, next_domain, &master->domains, list) {
+        list_del(&domain->list);
+        ec_domain_clear(domain);
+        kfree(domain);
+    }
+
+    master->command_index = 0;
+    master->debug_level = 0;
+    master->stats.timeouts = 0;
+    master->stats.delayed = 0;
+    master->stats.corrupted = 0;
+    master->stats.unmatched = 0;
+    master->stats.t_last = 0;
 }
 
 /*****************************************************************************/
@@ -122,12 +119,12 @@
 
 int ec_master_open(ec_master_t *master /**< Der EtherCAT-Master */)
 {
-    if (!master->device_registered) {
+    if (!master->device) {
         EC_ERR("No device registered!\n");
         return -1;
     }
 
-    if (ec_device_open(&master->device) < 0) {
+    if (ec_device_open(master->device)) {
         EC_ERR("Could not open device!\n");
         return -1;
     }
@@ -143,18 +140,265 @@
 
 void ec_master_close(ec_master_t *master /**< EtherCAT-Master */)
 {
-    if (!master->device_registered) {
+    if (!master->device) {
         EC_WARN("Warning - Trying to close an unregistered device!\n");
         return;
     }
 
-    if (ec_device_close(&master->device) < 0)
+    if (ec_device_close(master->device))
         EC_WARN("Warning - Could not close device!\n");
 }
 
 /*****************************************************************************/
 
 /**
+   Stellt ein Kommando in die Warteschlange.
+*/
+
+void ec_master_queue_command(ec_master_t *master, /**< EtherCAT-Master */
+                             ec_command_t *command /**< Kommando */
+                             )
+{
+    ec_command_t *queued_command;
+
+    // Ist das Kommando schon in der Warteschlange?
+    list_for_each_entry(queued_command, &master->commands, list) {
+        if (queued_command == command) {
+            command->state = EC_CMD_QUEUED;
+            if (unlikely(master->debug_level))
+                EC_WARN("command already queued.\n");
+            return;
+        }
+    }
+
+    list_add_tail(&command->list, &master->commands);
+    command->state = EC_CMD_QUEUED;
+}
+
+/*****************************************************************************/
+
+/**
+   Sendet die Kommandos in der Warteschlange.
+
+   \return 0 bei Erfolg, sonst < 0
+*/
+
+void ec_master_send_commands(ec_master_t *master /**< EtherCAT-Master */)
+{
+    ec_command_t *command;
+    size_t command_size;
+    uint8_t *frame_data, *cur_data;
+    void *follows_word;
+    cycles_t start = 0, end;
+
+    if (unlikely(master->debug_level > 0)) {
+        EC_DBG("ec_master_send\n");
+        start = get_cycles();
+    }
+
+    // Zeiger auf Socket-Buffer holen
+    frame_data = ec_device_tx_data(master->device);
+    cur_data = frame_data + EC_FRAME_HEADER_SIZE;
+    follows_word = NULL;
+
+    // Aktuellen Frame mit Kommandos füllen
+    list_for_each_entry(command, &master->commands, list) {
+        if (command->state != EC_CMD_QUEUED) continue;
+
+        // Passt das aktuelle Kommando noch in den aktuellen Rahmen?
+        command_size = EC_COMMAND_HEADER_SIZE + command->data_size
+            + EC_COMMAND_FOOTER_SIZE;
+        if (cur_data - frame_data + command_size > EC_MAX_FRAME_SIZE) break;
+
+        command->state = EC_CMD_SENT;
+        command->index = master->command_index++;
+
+        if (unlikely(master->debug_level > 0))
+            EC_DBG("adding command 0x%02X\n", command->index);
+
+        // Command-Following-Flag im letzten Kommando setzen
+        if (follows_word)
+            EC_WRITE_U16(follows_word, EC_READ_U16(follows_word) | 0x8000);
+
+        // EtherCAT command header
+        EC_WRITE_U8 (cur_data,     command->type);
+        EC_WRITE_U8 (cur_data + 1, command->index);
+        EC_WRITE_U32(cur_data + 2, command->address.logical);
+        EC_WRITE_U16(cur_data + 6, command->data_size & 0x7FF);
+        EC_WRITE_U16(cur_data + 8, 0x0000);
+        follows_word = cur_data + 6;
+        cur_data += EC_COMMAND_HEADER_SIZE;
+
+        // EtherCAT command data
+        memcpy(cur_data, command->data, command->data_size);
+        cur_data += command->data_size;
+
+        // EtherCAT command footer
+        EC_WRITE_U16(cur_data, command->working_counter);
+        cur_data += EC_COMMAND_FOOTER_SIZE;
+    }
+
+    if (cur_data - frame_data == EC_FRAME_HEADER_SIZE) {
+        if (unlikely(master->debug_level > 0)) EC_DBG("nothing to send.\n");
+        return;
+    }
+
+    // EtherCAT frame header
+    EC_WRITE_U16(frame_data, ((cur_data - frame_data
+                               - EC_FRAME_HEADER_SIZE) & 0x7FF) | 0x1000);
+
+    // Rahmen auffüllen
+    while (cur_data - frame_data < EC_MIN_FRAME_SIZE)
+        EC_WRITE_U8(cur_data++, 0x00);
+
+    if (unlikely(master->debug_level > 0))
+        EC_DBG("Frame size: %i\n", cur_data - frame_data);
+
+    // Send frame
+    ec_device_send(master->device, cur_data - frame_data);
+
+    if (unlikely(master->debug_level > 0)) {
+        end = get_cycles();
+        EC_DBG("ec_master_send finished in %ius.\n",
+               (u32) (end - start) * 1000 / cpu_khz);
+    }
+}
+
+/*****************************************************************************/
+
+/**
+   Wertet einen empfangenen Rahmen aus.
+
+   \return 0 bei Erfolg, sonst < 0
+*/
+
+void ec_master_receive(ec_master_t *master, /**< EtherCAT-Master */
+                      const uint8_t *frame_data, /**< Empfangene Daten */
+                      size_t size /**< Anzahl empfangene Datenbytes */
+                      )
+{
+    size_t frame_size, data_size;
+    uint8_t command_type, command_index;
+    unsigned int cmd_follows, matched;
+    const uint8_t *cur_data;
+    ec_command_t *command;
+
+    if (unlikely(size < EC_FRAME_HEADER_SIZE)) {
+        master->stats.corrupted++;
+        ec_master_output_stats(master);
+        return;
+    }
+
+    cur_data = frame_data;
+
+    // Länge des gesamten Frames prüfen
+    frame_size = EC_READ_U16(cur_data) & 0x07FF;
+    cur_data += EC_FRAME_HEADER_SIZE;
+
+    if (unlikely(frame_size > size)) {
+        master->stats.corrupted++;
+        ec_master_output_stats(master);
+        return;
+    }
+
+    cmd_follows = 1;
+    while (cmd_follows) {
+        // Kommando-Header auswerten
+        command_type  = EC_READ_U8 (cur_data);
+        command_index = EC_READ_U8 (cur_data + 1);
+        data_size     = EC_READ_U16(cur_data + 6) & 0x07FF;
+        cmd_follows   = EC_READ_U16(cur_data + 6) & 0x8000;
+        cur_data += EC_COMMAND_HEADER_SIZE;
+
+        if (unlikely(cur_data - frame_data
+                     + data_size + EC_COMMAND_FOOTER_SIZE > size)) {
+            master->stats.corrupted++;
+            ec_master_output_stats(master);
+            return;
+        }
+
+        // Suche passendes Kommando in der Liste
+        matched = 0;
+        list_for_each_entry(command, &master->commands, list) {
+            if (command->state == EC_CMD_SENT
+                && command->type == command_type
+                && command->index == command_index
+                && command->data_size == data_size) {
+                matched = 1;
+                break;
+            }
+        }
+
+        // Kein passendes Kommando in der Liste gefunden
+        if (!matched) {
+            master->stats.unmatched++;
+            ec_master_output_stats(master);
+            cur_data += data_size + EC_COMMAND_FOOTER_SIZE;
+            continue;
+        }
+
+        // Empfangene Daten in Kommando-Datenspeicher kopieren
+        memcpy(command->data, cur_data, data_size);
+        cur_data += data_size;
+
+        // Working-Counter setzen
+        command->working_counter = EC_READ_U16(cur_data);
+        cur_data += EC_COMMAND_FOOTER_SIZE;
+
+        // Kommando aus der Liste entfernen
+        command->state = EC_CMD_RECEIVED;
+        list_del_init(&command->list);
+    }
+}
+
+/*****************************************************************************/
+
+/**
+   Sendet ein einzelnes Kommando und wartet auf den Empfang.
+
+   Wenn der Slave nicht antwortet, wird das Kommando
+   nochmals gesendet.
+
+   \return 0 bei Erfolg, sonst < 0
+*/
+
+int ec_master_simple_io(ec_master_t *master, /**< EtherCAT-Master */
+                        ec_command_t *command /**< Kommando */
+                        )
+{
+    unsigned int response_tries_left;
+
+    response_tries_left = 10;
+    do
+    {
+        ec_master_queue_command(master, command);
+        EtherCAT_rt_master_xio(master);
+
+        if (command->state == EC_CMD_RECEIVED) {
+            break;
+        }
+        else if (command->state == EC_CMD_TIMEOUT) {
+            EC_ERR("Simple IO TIMED OUT!\n");
+            return -1;
+        }
+        else if (command->state == EC_CMD_ERROR) {
+            EC_ERR("Simple IO command error!\n");
+            return -1;
+        }
+    }
+    while (unlikely(!command->working_counter && --response_tries_left));
+
+    if (unlikely(!response_tries_left)) {
+        EC_ERR("No response in simple IO!\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+/*****************************************************************************/
+
+/**
    Durchsucht den EtherCAT-Bus nach Slaves.
 
    Erstellt ein Array mit allen Slave-Informationen die für den
@@ -163,9 +407,9 @@
    \return 0 bei Erfolg, sonst < 0
 */
 
-int ec_scan_for_slaves(ec_master_t *master /**< EtherCAT-Master */)
-{
-    ec_frame_t frame;
+int ec_master_bus_scan(ec_master_t *master /**< EtherCAT-Master */)
+{
+    ec_command_t command;
     ec_slave_t *slave;
     ec_slave_ident_t *ident;
     unsigned int i;
@@ -177,9 +421,9 @@
     }
 
     // Determine number of slaves on bus
-    ec_frame_init_brd(&frame, master, 0x0000, 4);
-    if (unlikely(ec_frame_send_receive(&frame))) return -1;
-    master->slave_count = frame.working_counter;
+    ec_command_init_brd(&command, 0x0000, 4);
+    if (unlikely(ec_master_simple_io(master, &command))) return -1;
+    master->slave_count = command.working_counter;
     EC_INFO("Found %i slaves on bus.\n", master->slave_count);
 
     if (!master->slave_count) return 0;
@@ -206,11 +450,9 @@
 
         // Write station address
         EC_WRITE_U16(data, slave->station_address);
-
-        ec_frame_init_apwr(&frame, master, slave->ring_position, 0x0010,
-                           sizeof(uint16_t), data);
-
-        if (unlikely(ec_frame_send_receive(&frame))) {
+        ec_command_init_apwr(&command, slave->ring_position,
+                             0x0010, sizeof(uint16_t), data);
+        if (unlikely(ec_master_simple_io(master, &command))) {
             EC_ERR("Writing station address failed on slave %i!\n", i);
             return -1;
         }
@@ -241,30 +483,36 @@
 /*****************************************************************************/
 
 /**
-   Ausgaben während des zyklischen Betriebs.
-
-   Diese Funktion sorgt dafür, dass Ausgaben (Zählerstände) während
-   des zyklischen Betriebs nicht zu oft getätigt werden.
+   Statistik-Ausgaben während des zyklischen Betriebs.
+
+   Diese Funktion sorgt dafür, dass Statistiken während des zyklischen
+   Betriebs bei Bedarf, aber nicht zu oft ausgegeben werden.
 
    Die Ausgabe erfolgt gesammelt höchstens einmal pro Sekunde.
 */
 
-void ec_cyclic_output(ec_master_t *master /**< EtherCAT-Master */)
-{
-    unsigned long int t;
-
-    rdtscl(t);
-
-    if ((t - master->t_last_cyclic_output) / cpu_khz > 1000) {
-        if (master->frames_lost) {
-            EC_WARN("%u frame(s) LOST!\n", master->frames_lost);
-            master->frames_lost = 0;
-        }
-        if (master->frames_delayed) {
-            EC_WARN("%u frame(s) DELAYED!\n", master->frames_delayed);
-            master->frames_delayed = 0;
-        }
-        master->t_last_cyclic_output = t;
+void ec_master_output_stats(ec_master_t *master /**< EtherCAT-Master */)
+{
+    cycles_t t_now = get_cycles();
+
+    if (unlikely((u32) (t_now - master->stats.t_last) / cpu_khz > 1000)) {
+        if (master->stats.timeouts) {
+            EC_WARN("%i commands TIMED OUT!\n", master->stats.timeouts);
+            master->stats.timeouts = 0;
+        }
+        if (master->stats.delayed) {
+            EC_WARN("%i frame(s) DELAYED!\n", master->stats.delayed);
+            master->stats.delayed = 0;
+        }
+        if (master->stats.corrupted) {
+            EC_WARN("%i frame(s) CORRUPTED!\n", master->stats.corrupted);
+            master->stats.corrupted = 0;
+        }
+        if (master->stats.unmatched) {
+            EC_WARN("%i command(s) UNMATCHED!\n", master->stats.unmatched);
+            master->stats.unmatched = 0;
+        }
+        master->stats.t_last = t_now;
     }
 }
 
@@ -283,11 +531,11 @@
    \return Zeiger auf Slave bei Erfolg, sonst NULL
 */
 
-ec_slave_t *ec_address(const ec_master_t *master,
-                       /**< EtherCAT-Master */
-                       const char *address
-                       /**< Address-String */
-                       )
+ec_slave_t *ec_master_slave_address(const ec_master_t *master,
+                                    /**< EtherCAT-Master */
+                                    const char *address
+                                    /**< Address-String */
+                                    )
 {
     unsigned long first, second;
     char *remainder, *remainder2;
@@ -448,13 +696,12 @@
 {
     unsigned int i, j;
     ec_slave_t *slave;
-    ec_frame_t frame;
+    ec_command_t command;
     const ec_sync_t *sync;
     const ec_slave_type_t *type;
     const ec_fmmu_t *fmmu;
     uint8_t data[256];
     uint32_t domain_offset;
-    unsigned int frame_count;
     ec_domain_t *domain;
 
     // Domains erstellen
@@ -464,10 +711,6 @@
             EC_ERR("Failed to allocate domain %X!\n", (u32) domain);
             return -1;
         }
-        frame_count = domain->data_size / EC_MAX_FRAME_SIZE + 1;
-        if (!domain->data_size) frame_count = 0;
-        EC_INFO("Domain %X - Allocated %i bytes (%i Frame(s))\n",
-                (u32) domain, domain->data_size, frame_count);
         domain_offset += domain->data_size;
     }
 
@@ -494,9 +737,9 @@
         // Resetting FMMUs
         if (slave->base_fmmu_count) {
             memset(data, 0x00, EC_FMMU_SIZE * slave->base_fmmu_count);
-            ec_frame_init_npwr(&frame, master, slave->station_address, 0x0600,
-                               EC_FMMU_SIZE * slave->base_fmmu_count, data);
-            if (unlikely(ec_frame_send_receive(&frame))) {
+            ec_command_init_npwr(&command, slave->station_address, 0x0600,
+                                 EC_FMMU_SIZE * slave->base_fmmu_count, data);
+            if (unlikely(ec_master_simple_io(master, &command))) {
                 EC_ERR("Resetting FMMUs failed on slave %i!\n",
                        slave->ring_position);
                 return -1;
@@ -506,9 +749,9 @@
         // Resetting Sync Manager channels
         if (slave->base_sync_count) {
             memset(data, 0x00, EC_SYNC_SIZE * slave->base_sync_count);
-            ec_frame_init_npwr(&frame, master, slave->station_address, 0x0800,
-                               EC_SYNC_SIZE * slave->base_sync_count, data);
-            if (unlikely(ec_frame_send_receive(&frame))) {
+            ec_command_init_npwr(&command, slave->station_address, 0x0800,
+                                 EC_SYNC_SIZE * slave->base_sync_count, data);
+            if (unlikely(ec_master_simple_io(master, &command))) {
                 EC_ERR("Resetting sync managers failed on slave %i!\n",
                        slave->ring_position);
                 return -1;
@@ -521,10 +764,10 @@
             sync = type->sync_managers[j];
 
             ec_sync_config(sync, data);
-            ec_frame_init_npwr(&frame, master, slave->station_address,
-                               0x0800 + j * EC_SYNC_SIZE, EC_SYNC_SIZE, data);
-
-            if (unlikely(ec_frame_send_receive(&frame))) {
+            ec_command_init_npwr(&command, slave->station_address,
+                                 0x0800 + j * EC_SYNC_SIZE, EC_SYNC_SIZE,
+                                 data);
+            if (unlikely(ec_master_simple_io(master, &command))) {
                 EC_ERR("Setting sync manager %i failed on slave %i!\n",
                        j, slave->ring_position);
                 return -1;
@@ -548,10 +791,10 @@
             fmmu = &slave->fmmus[j];
 
             ec_fmmu_config(fmmu, data);
-            ec_frame_init_npwr(&frame, master, slave->station_address,
-                               0x0600 + j * EC_FMMU_SIZE, EC_FMMU_SIZE, data);
-
-            if (unlikely(ec_frame_send_receive(&frame))) {
+            ec_command_init_npwr(&command, slave->station_address,
+                                 0x0600 + j * EC_FMMU_SIZE, EC_FMMU_SIZE,
+                                 data);
+            if (unlikely(ec_master_simple_io(master, &command))) {
                 EC_ERR("Setting FMMU %i failed on slave %i!\n",
                        j, slave->ring_position);
                 return -1;
@@ -600,9 +843,78 @@
 /*****************************************************************************/
 
 /**
+   Sendet und empfängt Kommandos.
+
+   \return 0 bei Erfolg, sonst < 0
+*/
+
+void EtherCAT_rt_master_xio(ec_master_t *master)
+{
+    ec_command_t *command, *next;
+    unsigned int commands_sent;
+    cycles_t t_start, t_end, t_timeout;
+
+    ec_master_output_stats(master);
+
+    if (unlikely(!master->device->link_state)) {
+        // Link DOWN, keines der Kommandos kann gesendet werden.
+        list_for_each_entry_safe(command, next, &master->commands, list) {
+            command->state = EC_CMD_ERROR;
+            list_del_init(&command->list);
+        }
+
+        // Device-Zustand abfragen
+        ec_device_call_isr(master->device);
+        return;
+    }
+
+    // Rahmen senden
+    ec_master_send_commands(master);
+
+    t_start = get_cycles(); // Sendezeit nehmen
+    t_timeout = 100 * cpu_khz / 1000; // 100us
+
+    do {
+        ec_device_call_isr(master->device);
+
+        t_end = get_cycles(); // Aktuelle Zeit nehmen
+        if (t_end - t_start >= t_timeout) break; // Timeout
+
+        commands_sent = 0;
+        list_for_each_entry_safe(command, next, &master->commands, list) {
+            if (command->state == EC_CMD_RECEIVED)
+                list_del_init(&command->list);
+            else if (command->state == EC_CMD_SENT)
+                commands_sent++;
+        }
+    } while (commands_sent);
+
+    // Zeit abgelaufen. Alle verbleibenden Kommandos entfernen.
+    list_for_each_entry_safe(command, next, &master->commands, list) {
+        switch (command->state) {
+            case EC_CMD_SENT:
+            case EC_CMD_QUEUED:
+                command->state = EC_CMD_TIMEOUT;
+                master->stats.timeouts++;
+                ec_master_output_stats(master);
+                break;
+            case EC_CMD_RECEIVED:
+                master->stats.delayed++;
+                ec_master_output_stats(master);
+                break;
+            default:
+                break;
+        }
+        list_del_init(&command->list);
+    }
+}
+
+/*****************************************************************************/
+
+/**
    Setzt die Debug-Ebene des Masters.
 
-   Folgende Debug-level sind definiert:
+   Folgende Debug-Level sind definiert:
 
    - 1: Nur Positionsmarken in bestimmten Funktionen
    - 2: Komplette Frame-Inhalte
@@ -614,9 +926,10 @@
                               /**< Debug-Level */
                               )
 {
-    master->debug_level = level;
-
-    EC_INFO("Master debug level set to %i.\n", level);
+    if (level != master->debug_level) {
+        master->debug_level = level;
+        EC_INFO("Master debug level set to %i.\n", level);
+    }
 }
 
 /*****************************************************************************/
@@ -632,11 +945,8 @@
     unsigned int i;
 
     EC_INFO("*** Begin master information ***\n");
-
-    for (i = 0; i < master->slave_count; i++) {
+    for (i = 0; i < master->slave_count; i++)
         ec_slave_print(&master->slaves[i]);
-    }
-
     EC_INFO("*** End master information ***\n");
 }
 
@@ -645,6 +955,7 @@
 EXPORT_SYMBOL(EtherCAT_rt_master_register_domain);
 EXPORT_SYMBOL(EtherCAT_rt_master_activate);
 EXPORT_SYMBOL(EtherCAT_rt_master_deactivate);
+EXPORT_SYMBOL(EtherCAT_rt_master_xio);
 EXPORT_SYMBOL(EtherCAT_rt_master_debug);
 EXPORT_SYMBOL(EtherCAT_rt_master_print);
 
--- a/master/master.h	Thu Mar 02 13:08:07 2006 +0000
+++ b/master/master.h	Mon Mar 06 15:12:34 2006 +0000
@@ -15,12 +15,27 @@
 
 #include "device.h"
 #include "slave.h"
-#include "frame.h"
 #include "domain.h"
 
 /*****************************************************************************/
 
 /**
+   EtherCAT-Rahmen-Statistiken.
+*/
+
+typedef struct
+{
+    unsigned int timeouts; /**< Kommando-Timeouts */
+    unsigned int delayed; /**< Verzögerte Kommandos */
+    unsigned int corrupted; /**< Verfälschte Rahmen */
+    unsigned int unmatched; /**< Unpassende Kommandos */
+    cycles_t t_last; /**< Timestamp-Counter bei der letzten Ausgabe */
+}
+ec_stats_t;
+
+/*****************************************************************************/
+
+/**
    EtherCAT-Master
 
    Verwaltet die EtherCAT-Slaves und kommuniziert mit
@@ -31,16 +46,12 @@
 {
     ec_slave_t *slaves; /**< Array von Slaves auf dem Bus */
     unsigned int slave_count; /**< Anzahl Slaves auf dem Bus */
-    ec_device_t device; /**< EtherCAT-Gerät */
-    unsigned int device_registered; /**< Ein Geraet hat sich registriert. */
+    ec_device_t *device; /**< EtherCAT-Gerät */
+    struct list_head commands; /**< Kommando-Liste */
     uint8_t command_index; /**< Aktueller Kommando-Index */
     struct list_head domains; /**< Liste der Prozessdatendomänen */
     int debug_level; /**< Debug-Level im Master-Code */
-    unsigned int bus_time; /**< Letzte Bus-Zeit in Mikrosekunden */
-    unsigned int frames_lost; /**< Anzahl verlorener Frames */
-    unsigned int frames_delayed; /**< Anzahl verzögerter Frames */
-    unsigned long t_last_cyclic_output; /**< Timer-Ticks bei den letzten
-                                           zyklischen Ausgaben */
+    ec_stats_t stats; /**< Rahmen-Statistiken */
 };
 
 /*****************************************************************************/
@@ -49,19 +60,23 @@
 void ec_master_init(ec_master_t *);
 void ec_master_clear(ec_master_t *);
 void ec_master_reset(ec_master_t *);
-void ec_master_clear_slaves(ec_master_t *);
+
+// IO
+void ec_master_receive(ec_master_t *, const uint8_t *, size_t);
+void ec_master_queue_command(ec_master_t *, ec_command_t *);
+int ec_master_simple_io(ec_master_t *, ec_command_t *);
 
 // Registration of devices
 int ec_master_open(ec_master_t *);
 void ec_master_close(ec_master_t *);
 
 // Slave management
-int ec_scan_for_slaves(ec_master_t *);
-ec_slave_t *ec_address(const ec_master_t *, const char *);
+int ec_master_bus_scan(ec_master_t *);
+ec_slave_t *ec_master_slave_address(const ec_master_t *, const char *);
 
 // Misc
-void ec_output_debug_data(const ec_master_t *);
-void ec_cyclic_output(ec_master_t *);
+void ec_master_debug(const ec_master_t *);
+void ec_master_output_stats(ec_master_t *);
 
 /*****************************************************************************/
 
--- a/master/module.c	Thu Mar 02 13:08:07 2006 +0000
+++ b/master/module.c	Mon Mar 06 15:12:34 2006 +0000
@@ -35,9 +35,9 @@
 #define EC_LIT(X) #X
 #define EC_STR(X) EC_LIT(X)
 
-#define COMPILE_INFO "Revision " EC_STR(EC_REV) \
-                     ", compiled by " EC_STR(EC_USER) \
-                     " at " EC_STR(EC_DATE)
+#define COMPILE_INFO "Revision " EC_STR(SVNREV) \
+                     ", compiled by " EC_STR(USER) \
+                     " at " __DATE__ " " __TIME__
 
 /*****************************************************************************/
 
@@ -155,38 +155,35 @@
                                    /**< Zeiger auf das Modul */
                                    )
 {
-    ec_device_t *device;
     ec_master_t *master;
 
+    if (!net_dev) {
+        EC_WARN("Device is NULL!\n");
+        return NULL;
+    }
+
     if (master_index >= ec_master_count) {
         EC_ERR("Master %i does not exist!\n", master_index);
         return NULL;
     }
 
-    if (!net_dev) {
-        EC_WARN("Device is NULL!\n");
-        return NULL;
-    }
-
     master = ec_masters + master_index;
 
-    if (master->device_registered) {
+    if (master->device) {
         EC_ERR("Master %i already has a device!\n", master_index);
         return NULL;
     }
 
-    device = &master->device;
-
-    if (ec_device_init(device, master) < 0) return NULL;
-
-    device->dev = net_dev;
-    device->tx_skb->dev = net_dev;
-    device->isr = isr;
-    device->module = module;
-
-    master->device_registered = 1;
-
-    return device;
+    if (!(master->device = (ec_device_t *) kmalloc(sizeof(ec_device_t),
+                                                   GFP_KERNEL))) {
+        EC_ERR("Failed allocating device!\n");
+        return NULL;
+    }
+
+    if (ec_device_init(master->device, master, net_dev, isr, module))
+        return NULL;
+
+    return master->device;
 }
 
 /*****************************************************************************/
@@ -210,13 +207,14 @@
 
     master = ec_masters + master_index;
 
-    if (!master->device_registered || &master->device != device) {
+    if (!master->device || master->device != device) {
         EC_WARN("Unable to unregister device!\n");
         return;
     }
 
-    master->device_registered = 0;
-    ec_device_clear(device);
+    ec_device_clear(master->device);
+    kfree(master->device);
+    master->device = NULL;
 }
 
 /******************************************************************************
@@ -253,22 +251,24 @@
 
     master = &ec_masters[index];
 
-    if (!master->device_registered) {
+    if (!master->device) {
         EC_ERR("Master %i has no device assigned yet!\n", index);
         goto req_return;
     }
 
-    if (!try_module_get(master->device.module)) {
+    if (!try_module_get(master->device->module)) {
         EC_ERR("Failed to reserve device module!\n");
         goto req_return;
     }
 
-    if (ec_master_open(master) < 0) {
+    if (ec_master_open(master)) {
         EC_ERR("Failed to open device!\n");
         goto req_module_put;
     }
 
-    if (ec_scan_for_slaves(master) != 0) {
+    if (!master->device->link_state) EC_WARN("Link is DOWN.\n");
+
+    if (ec_master_bus_scan(master) != 0) {
         EC_ERR("Bus scan failed!\n");
         goto req_close;
     }
@@ -282,7 +282,7 @@
     ec_master_close(master);
 
  req_module_put:
-    module_put(master->device.module);
+    module_put(master->device->module);
     ec_master_reset(master);
 
  req_return:
@@ -318,7 +318,7 @@
     ec_master_close(master);
     ec_master_reset(master);
 
-    module_put(master->device.module);
+    module_put(master->device->module);
     ec_masters_reserved[i] = 0;
 
     EC_INFO("===== Master %i stopped. =====\n", i);
--- a/master/slave.c	Thu Mar 02 13:08:07 2006 +0000
+++ b/master/slave.c	Mon Mar 06 15:12:34 2006 +0000
@@ -14,7 +14,8 @@
 #include "../include/EtherCAT_si.h"
 #include "globals.h"
 #include "slave.h"
-#include "frame.h"
+#include "command.h"
+#include "master.h"
 
 /*****************************************************************************/
 
@@ -64,23 +65,21 @@
 
 int ec_slave_fetch(ec_slave_t *slave /**< EtherCAT-Slave */)
 {
-    ec_frame_t frame;
+    ec_command_t command;
 
     // Read base data
-    ec_frame_init_nprd(&frame, slave->master, slave->station_address,
-                       0x0000, 6);
-
-    if (unlikely(ec_frame_send_receive(&frame))) {
+    ec_command_init_nprd(&command, slave->station_address, 0x0000, 6);
+    if (unlikely(ec_master_simple_io(slave->master, &command))) {
         EC_ERR("Reading base datafrom slave %i failed!\n",
                slave->ring_position);
         return -1;
     }
 
-    slave->base_type =       EC_READ_U8 (frame.data);
-    slave->base_revision =   EC_READ_U8 (frame.data + 1);
-    slave->base_build =      EC_READ_U16(frame.data + 2);
-    slave->base_fmmu_count = EC_READ_U8 (frame.data + 4);
-    slave->base_sync_count = EC_READ_U8 (frame.data + 5);
+    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);
 
     if (slave->base_fmmu_count > EC_MAX_FMMUS)
         slave->base_fmmu_count = EC_MAX_FMMUS;
@@ -130,9 +129,9 @@
                          der Daten */
                       )
 {
-    ec_frame_t frame;
+    ec_command_t command;
     unsigned char data[10];
-    unsigned int tries_left;
+    cycles_t start, end, timeout;
 
     // Initiate read operation
 
@@ -141,10 +140,8 @@
     EC_WRITE_U16(data + 2, offset);
     EC_WRITE_U16(data + 4, 0x0000);
 
-    ec_frame_init_npwr(&frame, slave->master, slave->station_address,
-                       0x502, 6, data);
-
-    if (unlikely(ec_frame_send_receive(&frame))) {
+    ec_command_init_npwr(&command, slave->station_address, 0x502, 6, data);
+    if (unlikely(ec_master_simple_io(slave->master, &command))) {
         EC_ERR("SII-read failed on slave %i!\n", slave->ring_position);
         return -1;
     }
@@ -153,29 +150,28 @@
     // in das Datenregister und löscht daraufhin ein Busy-Bit. Solange
     // den Status auslesen, bis das Bit weg ist.
 
-    tries_left = 100;
-    while (likely(tries_left))
+    start = get_cycles();
+    timeout = cpu_khz; // 1ms
+
+    do
     {
-        udelay(10);
-
-        ec_frame_init_nprd(&frame, slave->master, slave->station_address,
-                           0x502, 10);
-
-        if (unlikely(ec_frame_send_receive(&frame))) {
+        ec_command_init_nprd(&command, slave->station_address, 0x502, 10);
+        if (unlikely(ec_master_simple_io(slave->master, &command))) {
             EC_ERR("Getting SII-read status failed on slave %i!\n",
                    slave->ring_position);
             return -1;
         }
 
-        if (likely((EC_READ_U8(frame.data + 1) & 0x81) == 0)) {
-            memcpy(target, frame.data + 6, 4);
+        end = get_cycles();
+
+        if (likely((EC_READ_U8(command.data + 1) & 0x81) == 0)) {
+            memcpy(target, command.data + 6, 4);
             break;
         }
-
-        tries_left--;
-    }
-
-    if (unlikely(!tries_left)) {
+    }
+    while (likely((end - start) < timeout));
+
+    if (unlikely((end - start) >= timeout)) {
         EC_ERR("SSI-read. Slave %i timed out!\n", slave->ring_position);
         return -1;
     }
@@ -197,52 +193,49 @@
                         /**< Alter Zustand */
                         )
 {
-    ec_frame_t frame;
+    ec_command_t command;
     unsigned char data[2];
-    unsigned int tries_left;
+    cycles_t start, end, timeout;
 
     EC_WRITE_U16(data, state | EC_ACK);
 
-    ec_frame_init_npwr(&frame, slave->master, slave->station_address,
-                       0x0120, 2, data);
-
-    if (unlikely(ec_frame_send_receive(&frame))) {
+    ec_command_init_npwr(&command, slave->station_address, 0x0120, 2, data);
+    if (unlikely(ec_master_simple_io(slave->master, &command))) {
         EC_WARN("State %02X acknowledge failed on slave %i!\n",
                 state, slave->ring_position);
         return;
     }
 
-    tries_left = 100;
-    while (likely(tries_left))
+    start = get_cycles();
+    timeout = cpu_khz; // 1ms
+
+    do
     {
-        udelay(10);
-
-        ec_frame_init_nprd(&frame, slave->master, slave->station_address,
-                           0x0130, 2);
-
-        if (unlikely(ec_frame_send_receive(&frame))) {
+        ec_command_init_nprd(&command, slave->station_address, 0x0130, 2);
+        if (unlikely(ec_master_simple_io(slave->master, &command))) {
             EC_WARN("State %02X acknowledge checking failed on slave %i!\n",
                     state, slave->ring_position);
             return;
         }
 
-        if (unlikely(EC_READ_U8(frame.data) != state)) {
+        end = get_cycles();
+
+        if (unlikely(EC_READ_U8(command.data) != state)) {
             EC_WARN("Could not acknowledge state %02X on slave %i (code"
                     " %02X)!\n", state, slave->ring_position,
-                    EC_READ_U8(frame.data));
+                    EC_READ_U8(command.data));
             return;
         }
 
-        if (likely(EC_READ_U8(frame.data) == state)) {
+        if (likely(EC_READ_U8(command.data) == state)) {
             EC_INFO("Acknowleged state %02X on slave %i.\n", state,
                     slave->ring_position);
             return;
         }
-
-        tries_left--;
-    }
-
-    if (unlikely(!tries_left)) {
+    }
+    while (likely((end - start) < timeout));
+
+    if (unlikely((end - start) >= timeout)) {
         EC_WARN("Could not check state acknowledgement %02X of slave %i -"
                 " Timeout while checking!\n", state, slave->ring_position);
         return;
@@ -263,52 +256,51 @@
                           /**< Neuer Zustand */
                           )
 {
-    ec_frame_t frame;
+    ec_command_t command;
     unsigned char data[2];
-    unsigned int tries_left;
+    cycles_t start, end, timeout;
 
     EC_WRITE_U16(data, state);
 
-    ec_frame_init_npwr(&frame, slave->master, slave->station_address,
-                       0x0120, 2, data);
-
-    if (unlikely(ec_frame_send_receive(&frame))) {
+    ec_command_init_npwr(&command, slave->station_address, 0x0120, 2, data);
+    if (unlikely(ec_master_simple_io(slave->master, &command))) {
         EC_ERR("Failed to set state %02X on slave %i!\n",
                state, slave->ring_position);
         return -1;
     }
 
-    tries_left = 100;
-    while (likely(tries_left))
+    start = get_cycles();
+    timeout = cpu_khz; // 1ms
+
+    do
     {
-        udelay(10);
-
-        ec_frame_init_nprd(&frame, slave->master, slave->station_address,
-                           0x0130, 2);
-
-        if (unlikely(ec_frame_send_receive(&frame))) {
+        udelay(100); // Dem Slave etwas Zeit lassen...
+
+        ec_command_init_nprd(&command, slave->station_address, 0x0130, 2);
+        if (unlikely(ec_master_simple_io(slave->master, &command))) {
             EC_ERR("Failed to check state %02X on slave %i!\n",
                    state, slave->ring_position);
             return -1;
         }
 
-        if (unlikely(EC_READ_U8(frame.data) & 0x10)) { // State change error
+        end = get_cycles();
+
+        if (unlikely(EC_READ_U8(command.data) & 0x10)) { // State change error
             EC_ERR("Could not set state %02X - Slave %i refused state change"
                    " (code %02X)!\n", state, slave->ring_position,
-                   EC_READ_U8(frame.data));
-            ec_slave_state_ack(slave, EC_READ_U8(frame.data) & 0x0F);
+                   EC_READ_U8(command.data));
+            ec_slave_state_ack(slave, EC_READ_U8(command.data) & 0x0F);
             return -1;
         }
 
-        if (likely(EC_READ_U8(frame.data) == (state & 0x0F))) {
+        if (likely(EC_READ_U8(command.data) == (state & 0x0F))) {
             // State change successful
             break;
         }
-
-        tries_left--;
-    }
-
-    if (unlikely(!tries_left)) {
+    }
+    while (likely((end - start) < timeout));
+
+    if (unlikely((end - start) >= timeout)) {
         EC_ERR("Could not check state %02X of slave %i - Timeout!\n", state,
                slave->ring_position);
         return -1;
@@ -405,31 +397,27 @@
 
 int ec_slave_check_crc(ec_slave_t *slave /**< EtherCAT-Slave */)
 {
-    ec_frame_t frame;
+    ec_command_t command;
     uint8_t data[4];
 
-    ec_frame_init_nprd(&frame, slave->master, slave->station_address,
-                       0x0300, 4);
-
-    if (unlikely(ec_frame_send_receive(&frame))) {
+    ec_command_init_nprd(&command, slave->station_address, 0x0300, 4);
+    if (unlikely(ec_master_simple_io(slave->master, &command))) {
         EC_WARN("Reading CRC fault counters failed on slave %i!\n",
                 slave->ring_position);
         return -1;
     }
 
     // No CRC faults.
-    if (!EC_READ_U16(frame.data) && !EC_READ_U16(frame.data + 2)) return 0;
+    if (!EC_READ_U16(command.data) && !EC_READ_U16(command.data + 2)) return 0;
 
     EC_WARN("CRC faults on slave %i. A: %i, B: %i\n", slave->ring_position,
-            EC_READ_U16(frame.data), EC_READ_U16(frame.data + 2));
+            EC_READ_U16(command.data), EC_READ_U16(command.data + 2));
 
     // Reset CRC counters
     EC_WRITE_U16(data,     0x0000);
     EC_WRITE_U16(data + 2, 0x0000);
-    ec_frame_init_npwr(&frame, slave->master, slave->station_address,
-                       0x0300, 4, data);
-
-    if (unlikely(ec_frame_send_receive(&frame))) {
+    ec_command_init_npwr(&command, slave->station_address, 0x0300, 4, data);
+    if (unlikely(ec_master_simple_io(slave->master, &command))) {
         EC_WARN("Resetting CRC fault counters failed on slave %i!\n",
                 slave->ring_position);
         return -1;
--- a/master/slave.h	Thu Mar 02 13:08:07 2006 +0000
+++ b/master/slave.h	Mon Mar 06 15:12:34 2006 +0000
@@ -16,6 +16,28 @@
 /*****************************************************************************/
 
 /**
+   Zustand eines EtherCAT-Slaves.
+*/
+
+typedef enum
+{
+    EC_SLAVE_STATE_UNKNOWN = 0x00, /**< Status unbekannt */
+    EC_SLAVE_STATE_INIT = 0x01,    /**< Init-Zustand (Keine Mailbox-
+                                      Kommunikation, Kein I/O) */
+    EC_SLAVE_STATE_PREOP = 0x02,   /**< Pre-Operational (Mailbox-
+                                      Kommunikation, Kein I/O) */
+    EC_SLAVE_STATE_SAVEOP = 0x04,  /**< Save-Operational (Mailbox-
+                                      Kommunikation und Input Update) */
+    EC_SLAVE_STATE_OP = 0x08,      /**< Operational, (Mailbox-
+                                      Kommunikation und Input/Output Update) */
+    EC_ACK = 0x10                  /**< Acknoledge-Bit beim Zustandswechsel
+                                      (dies ist kein eigener Zustand) */
+}
+ec_slave_state_t;
+
+/*****************************************************************************/
+
+/**
    FMMU-Konfiguration.
 */
 
--- a/mini/mini.c	Thu Mar 02 13:08:07 2006 +0000
+++ b/mini/mini.c	Mon Mar 06 15:12:34 2006 +0000
@@ -17,7 +17,7 @@
 
 /*****************************************************************************/
 
-#define ABTASTFREQUENZ 1000
+#define ABTASTFREQUENZ 100
 
 struct timer_list timer;
 
@@ -47,7 +47,9 @@
     static unsigned int counter = 0;
 
     // Prozessdaten lesen und schreiben
-    EtherCAT_rt_domain_xio(domain1);
+    EtherCAT_rt_domain_queue(domain1);
+    EtherCAT_rt_master_xio(master);
+    EtherCAT_rt_domain_process(domain1);
 
     k_angle = EC_READ_U16(r_inc);
     k_pos   = EC_READ_U32(r_ssi);
--- a/rt/Makefile	Thu Mar 02 13:08:07 2006 +0000
+++ b/rt/Makefile	Mon Mar 06 15:12:34 2006 +0000
@@ -28,8 +28,9 @@
 		rt_lib/msr-math/msr_hex_bin.o \
 		libm.o
 
-EXTRA_CFLAGS := -I $(src)/rt_lib/msr-include -D_SIMULATION \
-		-I/usr/include -mhard-float
+EXTRA_CFLAGS := -I$(src)/rt_lib/msr-include -D_SIMULATION \
+		-I/usr/include -mhard-float \
+		-DSVNREV=$(shell svnversion $(src)) -DUSER=$(USER)
 
 #------------------------------------------------------------------------------
 
--- a/rt/msr_module.c	Thu Mar 02 13:08:07 2006 +0000
+++ b/rt/msr_module.c	Mon Mar 06 15:12:34 2006 +0000
@@ -50,9 +50,11 @@
 // EtherCAT
 ec_master_t *master = NULL;
 ec_domain_t *domain1 = NULL;
+ec_domain_t *domain2 = NULL;
 
 // Prozessdaten
 void *r_ssi;
+void *r_ssi2;
 void *r_inc;
 
 uint32_t k_angle;
@@ -60,19 +62,39 @@
 
 ec_field_init_t domain1_fields[] = {
     {&r_ssi,  "1", "Beckhoff", "EL5001", ec_ipvalue, 0, 1},
-    {&r_inc, "10", "Beckhoff", "EL5101", ec_ipvalue, 0, 1},
     {}
 };
 
+ec_field_init_t domain2_fields[] = {
+    {&r_ssi2,  "1", "Beckhoff", "EL5001", ec_ipvalue, 0, 1},
+    {}
+};
+
 /*****************************************************************************/
 
 static void msr_controller_run(void)
 {
+    static unsigned int counter = 0;
+
+    if (counter) counter--;
+    else {
+        //EtherCAT_rt_master_debug(master, 2);
+        counter = MSR_ABTASTFREQUENZ;
+    }
+
     // Prozessdaten lesen und schreiben
-    EtherCAT_rt_domain_xio(domain1);
-
-    k_angle = EC_READ_U16(r_inc);
+    EtherCAT_rt_domain_queue(domain1);
+    EtherCAT_rt_domain_queue(domain2);
+
+    EtherCAT_rt_master_xio(master);
+
+    EtherCAT_rt_domain_process(domain1);
+    EtherCAT_rt_domain_process(domain2);
+
+    //k_angle = EC_READ_U16(r_inc);
     k_pos = EC_READ_U32(r_ssi);
+
+    //EtherCAT_rt_master_debug(master, 0);
 }
 
 /*****************************************************************************/
@@ -118,7 +140,6 @@
 int __init init_rt_module(void)
 {
     struct ipipe_domain_attr attr; //ipipe
-    const ec_field_init_t *field;
     uint32_t version;
 
     // Als allererstes die RT-lib initialisieren
@@ -134,7 +155,7 @@
 
     //EtherCAT_rt_master_print(master);
 
-    printk(KERN_INFO "Registering domain...\n");
+    printk(KERN_INFO "Registering domains...\n");
 
     if (!(domain1 = EtherCAT_rt_master_register_domain(master, ec_sync, 100)))
     {
@@ -142,32 +163,37 @@
         goto out_release_master;
     }
 
+    if (!(domain2 = EtherCAT_rt_master_register_domain(master, ec_sync, 100)))
+    {
+        printk(KERN_ERR "EtherCAT: Could not register domain!\n");
+        goto out_release_master;
+    }
+
     printk(KERN_INFO "Registering domain fields...\n");
 
-    for (field = domain1_fields; field->data; field++)
-    {
-        if (!EtherCAT_rt_register_slave_field(domain1,
-                                              field->address,
-                                              field->vendor,
-                                              field->product,
-                                              field->data,
-                                              field->field_type,
-                                              field->field_index,
-                                              field->field_count)) {
-            printk(KERN_ERR "Could not register field!\n");
-            goto out_release_master;
-        }
+    if (EtherCAT_rt_register_domain_fields(domain1, domain1_fields)) {
+        printk(KERN_ERR "Failed to register domain fields.\n");
+        goto out_release_master;
+    }
+
+    if (EtherCAT_rt_register_domain_fields(domain2, domain2_fields)) {
+        printk(KERN_ERR "Failed to register domain fields.\n");
+        goto out_release_master;
     }
 
     printk(KERN_INFO "Activating master...\n");
 
+    //EtherCAT_rt_master_debug(master, 2);
+
     if (EtherCAT_rt_master_activate(master)) {
         printk(KERN_ERR "Could not activate master!\n");
         goto out_release_master;
     }
 
+    //EtherCAT_rt_master_debug(master, 0);
+
 #if 1
-    if (EtherCAT_rt_canopen_sdo_addr_read(master, "1", 0x100A, 1,
+    if (EtherCAT_rt_canopen_sdo_addr_read(master, "6", 0x100A, 1,
                                           &version)) {
         printk(KERN_ERR "Could not read SSI version!\n");
         goto out_release_master;
@@ -222,9 +248,16 @@
 
 /*****************************************************************************/
 
+#define EC_LIT(X) #X
+#define EC_STR(X) EC_LIT(X)
+#define COMPILE_INFO "Revision " EC_STR(SVNREV) \
+                     ", compiled by " EC_STR(USER) \
+                     " at " __DATE__ " " __TIME__
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR ("Florian Pose <fp@igh-essen.com>");
 MODULE_DESCRIPTION ("EtherCAT real-time test environment");
+MODULE_VERSION(COMPILE_INFO);
 
 module_init(init_rt_module);
 module_exit(cleanup_rt_module);