# HG changeset patch # User Florian Pose # Date 1141657954 0 # Node ID f564d0929292822cd841147f582969d143f4eb49 # Parent e6264685dd7b5ba75c34a7eec2c651b6277fe7b4 MERGE branches/async 222:233 -> trunk (Kommando-Warteschlangen). diff -r e6264685dd7b -r f564d0929292 devices/8139too.c --- a/devices/8139too.c Thu Mar 02 13:08:07 2006 +0000 +++ b/devices/8139too.c Mon Mar 06 15:12:34 2006 +0000 @@ -1804,21 +1804,16 @@ " (queue head)" : ""); tp->xstats.tx_timeouts++; - - /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ - - printk(KERN_DEBUG "%s: tx_timeout\n", dev->name); - - if (EtherCAT_dev_is_ec(rtl_ec_dev, dev)) - { - EtherCAT_dev_state(rtl_ec_dev, EC_DEVICE_STATE_TIMEOUT); - } + printk(KERN_DEBUG "%s: tx_timeout\n", dev->name); /* disable Tx ASAP, if not already */ tmp8 = RTL_R8 (ChipCmd); if (tmp8 & CmdTxEnb) RTL_W8 (ChipCmd, CmdRxEnb); + /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ + + if (!EtherCAT_dev_is_ec(rtl_ec_dev, dev)) { spin_lock(&tp->rx_lock); @@ -1840,7 +1835,7 @@ } spin_unlock(&tp->rx_lock); - } + } else { rtl8139_tx_clear (tp); @@ -1951,14 +1946,6 @@ tp->stats.tx_carrier_errors++; if (txstatus & TxOutOfWindow) tp->stats.tx_window_errors++; - - /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ - - if (EtherCAT_dev_is_ec(rtl_ec_dev, dev)) - EtherCAT_dev_state(rtl_ec_dev, EC_DEVICE_STATE_ERROR); - - /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ - } else { if (txstatus & TxUnderrun) { /* Add 64 to the Tx FIFO threshold. */ @@ -2033,15 +2020,6 @@ tp->xstats.rx_lost_in_ring++; } - /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ - - if (EtherCAT_dev_is_ec(rtl_ec_dev, dev)) - { - EtherCAT_dev_state(rtl_ec_dev, EC_DEVICE_STATE_ERROR); - } - - /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ - #ifndef CONFIG_8139_OLD_RX_RESET tmp8 = RTL_R8 (ChipCmd); RTL_W8 (ChipCmd, tmp8 & ~CmdRxEnb); diff -r e6264685dd7b -r f564d0929292 include/EtherCAT_dev.h --- 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); diff -r e6264685dd7b -r f564d0929292 include/EtherCAT_rt.h --- 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 diff -r e6264685dd7b -r f564d0929292 master/Makefile --- 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 #------------------------------------------------------------------------------ diff -r e6264685dd7b -r f564d0929292 master/canopen.c --- 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); } diff -r e6264685dd7b -r f564d0929292 master/command.c --- /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 +#include + +#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: *** +*/ diff -r e6264685dd7b -r f564d0929292 master/command.h --- /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 + +#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: *** +*/ diff -r e6264685dd7b -r f564d0929292 master/device.c --- 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); diff -r e6264685dd7b -r f564d0929292 master/device.h --- 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); /*****************************************************************************/ diff -r e6264685dd7b -r f564d0929292 master/domain.c --- 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); /*****************************************************************************/ diff -r e6264685dd7b -r f564d0929292 master/domain.h --- 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 */ }; diff -r e6264685dd7b -r f564d0929292 master/frame.c --- 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 -#include - -#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: *** -*/ diff -r e6264685dd7b -r f564d0929292 master/frame.h --- 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: *** -*/ diff -r e6264685dd7b -r f564d0929292 master/globals.h --- 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 diff -r e6264685dd7b -r f564d0929292 master/master.c --- 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); diff -r e6264685dd7b -r f564d0929292 master/master.h --- 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 *); /*****************************************************************************/ diff -r e6264685dd7b -r f564d0929292 master/module.c --- 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); diff -r e6264685dd7b -r f564d0929292 master/slave.c --- 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; diff -r e6264685dd7b -r f564d0929292 master/slave.h --- 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. */ diff -r e6264685dd7b -r f564d0929292 mini/mini.c --- 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); diff -r e6264685dd7b -r f564d0929292 rt/Makefile --- 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) #------------------------------------------------------------------------------ diff -r e6264685dd7b -r f564d0929292 rt/msr_module.c --- 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 "); MODULE_DESCRIPTION ("EtherCAT real-time test environment"); +MODULE_VERSION(COMPILE_INFO); module_init(init_rt_module); module_exit(cleanup_rt_module);