MERGE branches/async 222:233 -> trunk (Kommando-Warteschlangen).
--- 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);