# HG changeset patch # User Florian Pose # Date 1140688730 0 # Node ID 9f4ea66d89a36981ca652ccb6f330ba675256024 # Parent 7c986b717411f3a9f8719d40ed8bc9f1d5952cf1 Dynamische FMMU-Konfiguration, zwei Kopieroperationen eingespart, Einr?ckungen angepasst. diff -r 7c986b717411 -r 9f4ea66d89a3 Makefile --- a/Makefile Wed Feb 22 17:36:28 2006 +0000 +++ b/Makefile Thu Feb 23 09:58:50 2006 +0000 @@ -42,6 +42,6 @@ @echo >> $(CONFIG_FILE) @echo "$(CONFIG_FILE) erstellt." -#---------------------------------------------------------------- +#------------------------------------------------------------------------------ endif diff -r 7c986b717411 -r 9f4ea66d89a3 TODO --- a/TODO Wed Feb 22 17:36:28 2006 +0000 +++ b/TODO Thu Feb 23 09:58:50 2006 +0000 @@ -7,4 +7,5 @@ - Ethernet over EtherCAT (EoE) - eepro100-Kartentreiber - Proc/SysFS-Interface mit Baumdarstellung des Busses +- Anzahl unterstützter Sync-Manager/FMMUs auslesen diff -r 7c986b717411 -r 9f4ea66d89a3 devices/8139too.c --- a/devices/8139too.c Wed Feb 22 17:36:28 2006 +0000 +++ b/devices/8139too.c Thu Feb 23 09:58:50 2006 +0000 @@ -2268,14 +2268,12 @@ } else { - if (EtherCAT_dev_receive(rtl_ec_dev, - &rx_ring[ring_offset + 4] + ETH_HLEN, - pkt_size - ETH_HLEN) == 0) - { + EtherCAT_dev_receive(rtl_ec_dev, + &rx_ring[ring_offset + 4] + ETH_HLEN, + pkt_size - ETH_HLEN); dev->last_rx = jiffies; tp->stats.rx_bytes += pkt_size; tp->stats.rx_packets++; - } } /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ @@ -2466,7 +2464,7 @@ else { /* Beim EtherCAT-Device einfach alle Frames empfangen */ - rtl8139_rx(dev, tp, 100); // FIXME Das ist echt dirty... + rtl8139_rx(dev, tp, 100); // FIXME } } diff -r 7c986b717411 -r 9f4ea66d89a3 include/EtherCAT_dev.h --- a/include/EtherCAT_dev.h Wed Feb 22 17:36:28 2006 +0000 +++ b/include/EtherCAT_dev.h Thu Feb 23 09:58:50 2006 +0000 @@ -21,8 +21,11 @@ typedef enum { - EC_DEVICE_STATE_READY, EC_DEVICE_STATE_SENT, EC_DEVICE_STATE_RECEIVED, - EC_DEVICE_STATE_TIMEOUT, EC_DEVICE_STATE_ERROR + 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; @@ -33,9 +36,10 @@ struct pt_regs *), struct module *); void EtherCAT_dev_unregister(unsigned int, ec_device_t *); + int EtherCAT_dev_is_ec(ec_device_t *, struct net_device *); void EtherCAT_dev_state(ec_device_t *, ec_device_state_t); -int EtherCAT_dev_receive(ec_device_t *, void *, unsigned int); +void EtherCAT_dev_receive(ec_device_t *, void *, unsigned int); /*****************************************************************************/ diff -r 7c986b717411 -r 9f4ea66d89a3 include/EtherCAT_rt.h --- a/include/EtherCAT_rt.h Wed Feb 22 17:36:28 2006 +0000 +++ b/include/EtherCAT_rt.h Thu Feb 23 09:58:50 2006 +0000 @@ -14,106 +14,83 @@ struct ec_master; typedef struct ec_master ec_master_t; -struct ec_slave_type; -typedef struct ec_slave_type ec_slave_type_t; +struct ec_domain; +typedef struct ec_domain ec_domain_t; struct ec_slave; typedef struct ec_slave ec_slave_t; -struct ec_slave_init; -typedef struct ec_slave_init ec_slave_init_t; +typedef enum +{ + ec_sync, + ec_async +} +ec_domain_mode_t; + +typedef enum +{ + ec_status, + ec_control, + ec_ipvalue, + ec_opvalue +} +ec_field_type_t; + +typedef struct +{ + void **data; + const char *address; + const char *vendor; + const char *product; + ec_field_type_t field_type; + unsigned int field_index; + unsigned int field_count; +} +ec_field_init_t; /*****************************************************************************/ +// Master request functions ec_master_t *EtherCAT_rt_request_master(unsigned int master_index); void EtherCAT_rt_release_master(ec_master_t *master); -ec_slave_t *EtherCAT_rt_register_slave(ec_master_t *master, - const char *address, - const char *vendor_name, - const char *product_name, - int domain); +/*****************************************************************************/ +// Master methods -int EtherCAT_rt_register_slave_list(ec_master_t *master, - const ec_slave_init_t *slaves, - unsigned int count); +ec_domain_t *EtherCAT_rt_master_register_domain(ec_master_t *master, + ec_domain_mode_t mode, + unsigned int timeout_us); -int EtherCAT_rt_activate_slaves(ec_master_t *master); +int EtherCAT_rt_master_activate(ec_master_t *master); -int EtherCAT_rt_deactivate_slaves(ec_master_t *master); +int EtherCAT_rt_master_deactivate(ec_master_t *master); -int EtherCAT_rt_domain_xio(ec_master_t *master, unsigned int domain, - unsigned int timeout_us); +void EtherCAT_rt_master_debug(ec_master_t *master, int level); +void EtherCAT_rt_master_print(const ec_master_t *master); -void EtherCAT_rt_debug_level(ec_master_t *master, int level); +/*****************************************************************************/ +// Domain Methods -int EtherCAT_rt_canopen_sdo_write(ec_master_t *master, ec_slave_t *slave, +ec_slave_t *EtherCAT_rt_register_slave_field(ec_domain_t *domain, + const char *address, + const char *vendor_name, + const char *product_name, + void **data_ptr, + ec_field_type_t field_type, + unsigned int field_index, + unsigned int field_count); + +int EtherCAT_rt_domain_xio(ec_domain_t *domain); + +/*****************************************************************************/ +// Slave Methods + +int EtherCAT_rt_canopen_sdo_write(ec_slave_t *slave, unsigned int sdo_index, unsigned char sdo_subindex, - unsigned int value, unsigned int size); - -/*****************************************************************************/ - -/** - EtherCAT-Slave -*/ - -struct ec_slave -{ - // Base data - unsigned char base_type; /**< Slave-Typ */ - unsigned char base_revision; /**< Revision */ - unsigned short base_build; /**< Build-Nummer */ - - // Addresses - short ring_position; /**< (Negative) Position des Slaves im Bus */ - unsigned short station_address; /**< Konfigurierte Slave-Adresse */ - - // Slave information interface - unsigned int sii_vendor_id; /**< Identifikationsnummer des Herstellers */ - unsigned int sii_product_code; /**< Herstellerspezifischer Produktcode */ - unsigned int sii_revision_number; /**< Revisionsnummer */ - unsigned int sii_serial_number; /**< Seriennummer der Klemme */ - - const ec_slave_type_t *type; /**< Zeiger auf die Beschreibung - des Slave-Typs */ - - unsigned int logical_address; /**< Konfigurierte, logische Adresse */ - - void *process_data; /**< Zeiger auf den Speicherbereich - innerhalb eines Prozessdatenobjekts */ - void *private_data; /**< Zeiger auf privaten Datenbereich */ - int (*configure)(ec_slave_t *); /**< Zeiger auf die Funktion zur - Konfiguration */ - - unsigned char registered; /**< Der Slave wurde registriert */ - - unsigned int domain; /**< Prozessdatendomäne */ - - int error_reported; /**< Ein Zugriffsfehler wurde bereits gemeldet */ -}; - -/*****************************************************************************/ - -/** - Beschreibung eines EtherCAT-Slave-Typs. - - Diese Beschreibung dient zur Konfiguration einer bestimmten - Slave-Art. Sie enthält die Konfigurationsdaten für die - Slave-internen Sync-Manager und FMMU's. -*/ - -struct ec_slave_init -{ - ec_slave_t **slave_ptr; /**< Zeiger auf den Slave-Zeiger, der später auf - die Slave-Struktur zeigen soll. */ - const char *address; /**< ASCII-kodierte Bus-Adresse des zu - registrierenden Slaves \sa ec_address */ - const char *vendor_name; /**< Name des Herstellers */ - const char *product_name; /**< Name des Slaves-Typs */ - unsigned int domain; /**< Domäne, in der registriert werden soll. */ -}; + unsigned int value, + unsigned int size); /*****************************************************************************/ diff -r 7c986b717411 -r 9f4ea66d89a3 master/Makefile --- a/master/Makefile Wed Feb 22 17:36:28 2006 +0000 +++ b/master/Makefile Thu Feb 23 09:58:50 2006 +0000 @@ -15,7 +15,7 @@ obj-m := ec_master.o -ec_master-objs := module.o master.o device.o slave.o command.o types.o \ +ec_master-objs := module.o master.o device.o slave.o frame.o types.o \ domain.o canopen.o REV = `svnversion $(src)` diff -r 7c986b717411 -r 9f4ea66d89a3 master/canopen.c --- a/master/canopen.c Wed Feb 22 17:36:28 2006 +0000 +++ b/master/canopen.c Thu Feb 23 09:58:50 2006 +0000 @@ -18,16 +18,26 @@ /*****************************************************************************/ -int EtherCAT_rt_canopen_sdo_write(ec_master_t *master, ec_slave_t *slave, - unsigned int sdo_index, - unsigned char sdo_subindex, - unsigned int value, unsigned int size) +/** + Schreibt ein CANopen-SDO (service data object). + */ + +int EtherCAT_rt_canopen_sdo_write( + ec_slave_t *slave, /**< EtherCAT-Slave */ + unsigned int sdo_index, /**< SDO-Index */ + unsigned char sdo_subindex, /**< SDO-Subindex */ + unsigned int value, /**< Neuer Wert */ + unsigned int size /**< Größe des Datenfeldes */ + ) { unsigned char data[0xF6]; - ec_command_t cmd; + ec_frame_t frame; unsigned int tries_left, i; + ec_master_t *master; - for (i = 0; i < 0xF6; i++) data[i] = 0x00; + memset(data, 0x00, 0xF6); + + master = slave->master; if (size == 0 || size > 4) { printk(KERN_ERR "EtherCAT: Illegal SDO data size: %i!\n", size); @@ -55,14 +65,14 @@ value >>= 8; } - ec_command_write(&cmd, slave->station_address, 0x1800, 0xF6, data); + ec_frame_init_npwr(&frame, master, slave->station_address, 0x1800, 0xF6, + data); - if (unlikely(ec_simple_send_receive(master, &cmd) < 0)) - return -1; + if (unlikely(ec_frame_send_receive(&frame) < 0)) return -1; - if (unlikely(cmd.working_counter != 1)) { + if (unlikely(frame.working_counter != 1)) { printk(KERN_ERR "EtherCAT: Mailbox send - Slave %i did not respond!\n", - slave->ring_position * (-1)); + slave->ring_position); return -1; } @@ -71,18 +81,17 @@ tries_left = 10; while (tries_left) { - ec_command_read(&cmd, slave->station_address, 0x808, 8); + ec_frame_init_nprd(&frame, master, slave->station_address, 0x808, 8); - if (unlikely(ec_simple_send_receive(master, &cmd) < 0)) - return -1; + if (unlikely(ec_frame_send_receive(&frame) < 0)) return -1; - if (unlikely(cmd.working_counter != 1)) { + if (unlikely(frame.working_counter != 1)) { printk(KERN_ERR "EtherCAT: Mailbox check - Slave %i did not" - " respond!\n", slave->ring_position * (-1)); + " respond!\n", slave->ring_position); return -1; } - if (cmd.data[5] & 8) { // Written bit is high + if (frame.data[5] & 8) { // Written bit is high break; } @@ -92,30 +101,29 @@ if (!tries_left) { printk(KERN_ERR "EtherCAT: Mailbox check - Slave %i timed out.\n", - slave->ring_position * (-1)); + slave->ring_position); return -1; } - ec_command_read(&cmd, slave->station_address, 0x18F6, 0xF6); + ec_frame_init_nprd(&frame, master, slave->station_address, 0x18F6, 0xF6); - if (unlikely(ec_simple_send_receive(master, &cmd) < 0)) - return -1; + if (unlikely(ec_frame_send_receive(&frame) < 0)) return -1; - if (unlikely(cmd.working_counter != 1)) { + if (unlikely(frame.working_counter != 1)) { printk(KERN_ERR "EtherCAT: Mailbox receive - Slave %i did not" - " respond!\n", slave->ring_position * (-1)); + " respond!\n", slave->ring_position); return -1; } - if (cmd.data[5] != 0x03 // COE - || (cmd.data[7] >> 4) != 0x03 // SDO response - || (cmd.data[8] >> 5) != 0x03 // Initiate download response - || (cmd.data[9] != (sdo_index & 0xFF)) // Index - || (cmd.data[10] != ((sdo_index >> 8) & 0xFF)) - || (cmd.data[11] != sdo_subindex)) // Subindex + if (frame.data[5] != 0x03 // COE + || (frame.data[7] >> 4) != 0x03 // SDO response + || (frame.data[8] >> 5) != 0x03 // Initiate download response + || (frame.data[9] != (sdo_index & 0xFF)) // Index + || (frame.data[10] != ((sdo_index >> 8) & 0xFF)) + || (frame.data[11] != sdo_subindex)) // Subindex { printk(KERN_ERR "EtherCAT: Illegal mailbox response at slave %i!\n", - slave->ring_position * (-1)); + slave->ring_position); return -1; } diff -r 7c986b717411 -r 9f4ea66d89a3 master/canopen.h --- a/master/canopen.h Wed Feb 22 17:36:28 2006 +0000 +++ b/master/canopen.h Thu Feb 23 09:58:50 2006 +0000 @@ -17,3 +17,9 @@ /*****************************************************************************/ #endif + +/* Emacs-Konfiguration +;;; Local Variables: *** +;;; c-basic-offset:4 *** +;;; End: *** +*/ diff -r 7c986b717411 -r 9f4ea66d89a3 master/command.c --- a/master/command.c Wed Feb 22 17:36:28 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,250 +0,0 @@ -/****************************************************************************** - * - * c o m m a n d . c - * - * Methoden für ein EtherCAT-Kommando. - * - * $Id$ - * - *****************************************************************************/ - -#include - -#include "command.h" - -/*****************************************************************************/ - -/** - Kommando-Konstruktor. - - Initialisiert alle Variablen innerhalb des Kommandos auf die - Default-Werte. - - @param cmd Zeiger auf das zu initialisierende Kommando. -*/ - -void ec_command_init(ec_command_t *cmd) -{ - cmd->type = EC_COMMAND_NONE; - cmd->address.logical = 0x00000000; - cmd->data_length = 0; - cmd->state = EC_COMMAND_STATE_READY; - cmd->index = 0; - cmd->working_counter = 0; -} - -/*****************************************************************************/ - -/** - Kommando-Destruktor. - - Setzt alle Attribute auf den Anfangswert zurueck. - - @param cmd Zeiger auf das zu initialisierende Kommando. -*/ - -void ec_command_clear(ec_command_t *cmd) -{ - ec_command_init(cmd); -} - -/*****************************************************************************/ - -#define EC_FUNC_HEADER \ - ec_command_init(cmd) - -#define EC_FUNC_WRITE_FOOTER \ - cmd->data_length = length; \ - memcpy(cmd->data, data, length); - -#define EC_FUNC_READ_FOOTER \ - cmd->data_length = length; - -/*****************************************************************************/ - -/** - Initialisiert ein EtherCAT-NPRD-Kommando. - - @param cmd Zeiger auf das Kommando - @param node_address Adresse des Knotens (Slaves) - @param offset Physikalische Speicheradresse im Slave - @param length Länge der zu lesenden Daten -*/ - -void ec_command_read(ec_command_t *cmd, unsigned short node_address, - unsigned short offset, unsigned int length) -{ - if (unlikely(node_address == 0x0000)) - printk(KERN_WARNING "EtherCAT: Warning - Using node address 0x0000!\n"); - - EC_FUNC_HEADER; - - cmd->type = EC_COMMAND_NPRD; - cmd->address.phy.dev.node = node_address; - cmd->address.phy.mem = offset; - - EC_FUNC_READ_FOOTER; -} - -/*****************************************************************************/ - -/** - Initialisiert ein EtherCAT-NPWR-Kommando. - - Alloziert ein "node-adressed physical write"-Kommando - und fügt es in die Liste des Masters ein. - - @param cmd Zeiger auf das Kommando - @param node_address Adresse des Knotens (Slaves) - @param offset Physikalische Speicheradresse im Slave - @param length Länge der zu schreibenden Daten - @param data Zeiger auf Speicher mit zu schreibenden Daten -*/ - -void ec_command_write(ec_command_t *cmd, unsigned short node_address, - unsigned short offset, unsigned int length, - const unsigned char *data) -{ - if (unlikely(node_address == 0x0000)) - printk(KERN_WARNING "EtherCAT: Warning - Using node address 0x0000!\n"); - - EC_FUNC_HEADER; - - cmd->type = EC_COMMAND_NPWR; - cmd->address.phy.dev.node = node_address; - cmd->address.phy.mem = offset; - - EC_FUNC_WRITE_FOOTER; -} - -/*****************************************************************************/ - -/** - Initialisiert ein EtherCAT-APRD-Kommando. - - Alloziert ein "autoincerement physical read"-Kommando - und fügt es in die Liste des Masters ein. - - @param cmd Zeiger auf das Kommando - @param ring_position (Negative) Position des Slaves im Bus - @param offset Physikalische Speicheradresse im Slave - @param length Länge der zu lesenden Daten -*/ - -void ec_command_position_read(ec_command_t *cmd, short ring_position, - unsigned short offset, unsigned int length) -{ - EC_FUNC_HEADER; - - cmd->type = EC_COMMAND_APRD; - cmd->address.phy.dev.pos = ring_position; - cmd->address.phy.mem = offset; - - EC_FUNC_READ_FOOTER; -} - -/*****************************************************************************/ - -/** - Initialisiert ein EtherCAT-APWR-Kommando. - - Alloziert ein "autoincrement physical write"-Kommando - und fügt es in die Liste des Masters ein. - - @param cmd Zeiger auf das Kommando - @param ring_position (Negative) Position des Slaves im Bus - @param offset Physikalische Speicheradresse im Slave - @param length Länge der zu schreibenden Daten - @param data Zeiger auf Speicher mit zu schreibenden Daten -*/ - -void ec_command_position_write(ec_command_t *cmd, short ring_position, - unsigned short offset, unsigned int length, - const unsigned char *data) -{ - EC_FUNC_HEADER; - - cmd->type = EC_COMMAND_APWR; - cmd->address.phy.dev.pos = ring_position; - cmd->address.phy.mem = offset; - - EC_FUNC_WRITE_FOOTER; -} - -/*****************************************************************************/ - -/** - Initialisiert ein EtherCAT-BRD-Kommando. - - Alloziert ein "broadcast read"-Kommando - und fügt es in die Liste des Masters ein. - - @param cmd Zeiger auf das Kommando - @param offset Physikalische Speicheradresse im Slave - @param length Länge der zu lesenden Daten -*/ - -void ec_command_broadcast_read(ec_command_t *cmd, unsigned short offset, - unsigned int length) -{ - EC_FUNC_HEADER; - - cmd->type = EC_COMMAND_BRD; - cmd->address.phy.dev.node = 0x0000; - cmd->address.phy.mem = offset; - - EC_FUNC_READ_FOOTER; -} - -/*****************************************************************************/ - -/** - Initialisiert ein EtherCAT-BWR-Kommando. - - Alloziert ein "broadcast write"-Kommando - und fügt es in die Liste des Masters ein. - - @param cmd Zeiger auf das Kommando - @param offset Physikalische Speicheradresse im Slave - @param length Länge der zu schreibenden Daten - @param data Zeiger auf Speicher mit zu schreibenden Daten -*/ - -void ec_command_broadcast_write(ec_command_t *cmd, unsigned short offset, - unsigned int length, const unsigned char *data) -{ - EC_FUNC_HEADER; - - cmd->type = EC_COMMAND_BWR; - cmd->address.phy.dev.node = 0x0000; - cmd->address.phy.mem = offset; - - EC_FUNC_WRITE_FOOTER; -} - -/*****************************************************************************/ - -/** - Initialisiert ein EtherCAT-LRW-Kommando. - - Alloziert ein "logical read write"-Kommando - und fügt es in die Liste des Masters ein. - - @param cmd Zeiger auf das Kommando - @param offset Logische Speicheradresse - @param length Länge der zu lesenden/schreibenden Daten - @param data Zeiger auf Speicher mit zu lesenden/schreibenden Daten -*/ - -void ec_command_logical_read_write(ec_command_t *cmd, unsigned int offset, - unsigned int length, unsigned char *data) -{ - EC_FUNC_HEADER; - - cmd->type = EC_COMMAND_LRW; - cmd->address.logical = offset; - - EC_FUNC_WRITE_FOOTER; -} - -/*****************************************************************************/ diff -r 7c986b717411 -r 9f4ea66d89a3 master/command.h --- a/master/command.h Wed Feb 22 17:36:28 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,102 +0,0 @@ -/****************************************************************************** - * - * c o m m a n d . h - * - * Struktur für ein EtherCAT-Kommando. - * - * $Id$ - * - *****************************************************************************/ - -#ifndef _EC_COMMAND_H_ -#define _EC_COMMAND_H_ - -#include "globals.h" - -/*****************************************************************************/ - -/** - Status eines EtherCAT-Kommandos. -*/ - -typedef enum -{ - EC_COMMAND_STATE_READY, EC_COMMAND_STATE_SENT, EC_COMMAND_STATE_RECEIVED -} -ec_command_state_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 - { - union - { - short pos; /**< (Negative) Ring-Position des Slaves */ - unsigned short node; /**< Konfigurierte Knotenadresse */ - } - dev; - - unsigned short mem; /**< Physikalische Speicheradresse im Slave */ - } - phy; /**< Physikalische Adresse */ - - unsigned long logical; /**< Logische Adresse */ - unsigned char raw[4]; /**< Rohdaten für die Generierung des Frames */ -} -ec_address_t; - -/*****************************************************************************/ - -/** - EtherCAT-Kommando. -*/ - -typedef struct ec_command -{ - ec_command_type_t type; /**< Typ des Kommandos (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 */ - ec_command_state_t state; /**< Zustand des Kommandos - (bereit, gesendet, etc) */ - unsigned char index; /**< Kommando-Index, mit der das Kommando gesendet - wurde (wird vom Master beim Senden gesetzt. */ - unsigned int working_counter; /**< Working-Counter bei Empfang (wird - vom Master gesetzt) */ - unsigned char data[EC_FRAME_SIZE]; /**< Kommandodaten */ -} -ec_command_t; - -/*****************************************************************************/ - -void ec_command_read(ec_command_t *, unsigned short, unsigned short, - unsigned int); -void ec_command_write(ec_command_t *, unsigned short, unsigned short, - unsigned int, const unsigned char *); -void ec_command_position_read(ec_command_t *, short, unsigned short, - unsigned int); -void ec_command_position_write(ec_command_t *, short, unsigned short, - unsigned int, const unsigned char *); -void ec_command_broadcast_read(ec_command_t *, unsigned short, unsigned int); -void ec_command_broadcast_write(ec_command_t *, unsigned short, unsigned int, - const unsigned char *); -void ec_command_logical_read_write(ec_command_t *, unsigned int, unsigned int, - unsigned char *); - -/*****************************************************************************/ - -#endif diff -r 7c986b717411 -r 9f4ea66d89a3 master/device.c --- a/master/device.c Wed Feb 22 17:36:28 2006 +0000 +++ b/master/device.c Thu Feb 23 09:58:50 2006 +0000 @@ -29,32 +29,22 @@ int ec_device_init(ec_device_t *ecd) { - ecd->dev = NULL; - ecd->open = 0; - ecd->tx_time = 0; - ecd->rx_time = 0; - ecd->tx_intr_cnt = 0; - ecd->rx_intr_cnt = 0; - ecd->intr_cnt = 0; - ecd->state = EC_DEVICE_STATE_READY; - ecd->rx_data_length = 0; - ecd->isr = NULL; - ecd->module = NULL; - ecd->error_reported = 0; - - if ((ecd->tx_skb = dev_alloc_skb(EC_FRAME_SIZE)) == NULL) { - printk(KERN_ERR "EtherCAT: Could not allocate device tx socket buffer!\n"); - return -1; - } - - if ((ecd->rx_skb = dev_alloc_skb(EC_FRAME_SIZE)) == NULL) { - dev_kfree_skb(ecd->tx_skb); - ecd->tx_skb = NULL; - printk(KERN_ERR "EtherCAT: Could not allocate device rx socket buffer!\n"); - return -1; - } - - return 0; + ecd->dev = NULL; + ecd->open = 0; + ecd->tx_time = 0; + ecd->rx_time = 0; + ecd->state = EC_DEVICE_STATE_READY; + ecd->rx_data_length = 0; + ecd->isr = NULL; + ecd->module = NULL; + ecd->error_reported = 0; + + if ((ecd->tx_skb = dev_alloc_skb(ETH_HLEN + EC_MAX_FRAME_SIZE)) == NULL) { + printk(KERN_ERR "EtherCAT: Error allocating device socket buffer!\n"); + return -1; + } + + return 0; } /*****************************************************************************/ @@ -70,19 +60,14 @@ void ec_device_clear(ec_device_t *ecd) { - if (ecd->open) ec_device_close(ecd); - - ecd->dev = NULL; - - if (ecd->tx_skb) { - dev_kfree_skb(ecd->tx_skb); - ecd->tx_skb = NULL; - } - - if (ecd->rx_skb) { - dev_kfree_skb(ecd->rx_skb); - ecd->rx_skb = NULL; - } + if (ecd->open) ec_device_close(ecd); + + ecd->dev = NULL; + + if (ecd->tx_skb) { + dev_kfree_skb(ecd->tx_skb); + ecd->tx_skb = NULL; + } } /*****************************************************************************/ @@ -102,34 +87,32 @@ int ec_device_open(ec_device_t *ecd) { - unsigned int i; - - if (!ecd) { - printk(KERN_ERR "EtherCAT: Trying to open a NULL device!\n"); - return -1; - } - - if (!ecd->dev) { - printk(KERN_ERR "EtherCAT: No net_device to open!\n"); - return -1; - } - - if (ecd->open) { - printk(KERN_WARNING "EtherCAT: Device already opened!\n"); - } - else { - // Device could have received frames before - for (i = 0; i < 4; i++) ec_device_call_isr(ecd); - - // Reset old device state - ecd->state = EC_DEVICE_STATE_READY; - ecd->tx_intr_cnt = 0; - ecd->rx_intr_cnt = 0; - - if (ecd->dev->open(ecd->dev) == 0) ecd->open = 1; - } - - return ecd->open ? 0 : -1; + unsigned int i; + + if (!ecd) { + printk(KERN_ERR "EtherCAT: Trying to open a NULL device!\n"); + return -1; + } + + if (!ecd->dev) { + printk(KERN_ERR "EtherCAT: No net_device to open!\n"); + return -1; + } + + if (ecd->open) { + printk(KERN_WARNING "EtherCAT: Device already opened!\n"); + } + else { + // Device could have received frames before + for (i = 0; i < 4; i++) ec_device_call_isr(ecd); + + // Reset old device state + ecd->state = EC_DEVICE_STATE_READY; + + if (ecd->dev->open(ecd->dev) == 0) ecd->open = 1; + } + + return ecd->open ? 0 : -1; } /*****************************************************************************/ @@ -140,27 +123,42 @@ @param ecd EtherCAT-Gerät @return 0 bei Erfolg, < 0: Kein Gerät zum Schliessen oder - Schliessen fehlgeschlagen. + Schliessen fehlgeschlagen. */ int ec_device_close(ec_device_t *ecd) { - if (!ecd->dev) { - printk(KERN_ERR "EtherCAT: No device to close!\n"); - return -1; - } - - if (!ecd->open) { - printk(KERN_WARNING "EtherCAT: Device already closed!\n"); - } - else { - printk(KERN_INFO "EtherCAT: Stopping device (txcnt: %u, rxcnt: %u)\n", - (unsigned int) ecd->tx_intr_cnt, (unsigned int) ecd->rx_intr_cnt); - - if (ecd->dev->stop(ecd->dev) == 0) ecd->open = 0; - } - - return !ecd->open ? 0 : -1; + if (!ecd->dev) { + printk(KERN_ERR "EtherCAT: No device to close!\n"); + return -1; + } + + if (!ecd->open) { + printk(KERN_WARNING "EtherCAT: Device already closed!\n"); + } + else { + if (ecd->dev->stop(ecd->dev) == 0) ecd->open = 0; + } + + return !ecd->open ? 0 : -1; +} + +/*****************************************************************************/ + +/** + Bereitet den geräteinternen Socket-Buffer auf den Versand vor. + + \return Zeiger auf den Speicher, in den die Frame-Daten sollen. +*/ + +uint8_t *ec_device_prepare(ec_device_t *ecd /**< EtherCAT-Gerät */) +{ + // Clear transmit socket buffer and reserve space for Ethernet-II header + skb_trim(ecd->tx_skb, 0); + skb_reserve(ecd->tx_skb, ETH_HLEN); + + // Erstmal Speicher für maximal langen Frame reservieren + return skb_put(ecd->tx_skb, EC_MAX_FRAME_SIZE); } /*****************************************************************************/ @@ -172,115 +170,72 @@ Buffer, fügt den Ethernat-II-Header hinzu und ruft die start_xmit()-Funktion der Netzwerkkarte auf. - @param ecd EtherCAT-Gerät - @param data Zeiger auf die zu sendenden Daten - @param length Länge der zu sendenden Daten - - @return 0 bei Erfolg, < 0: Vorheriger Rahmen noch + \return 0 bei Erfolg, < 0: Vorheriger Rahmen noch nicht empfangen, oder kein Speicher mehr vorhanden */ -int ec_device_send(ec_device_t *ecd, unsigned char *data, unsigned int length) -{ - unsigned char *frame_data; - struct ethhdr *eth; - - if (unlikely(ecd->state == EC_DEVICE_STATE_SENT)) { - printk(KERN_WARNING "EtherCAT: Warning - Trying to send frame while last " - " was not received!\n"); - } - - // Clear transmit socket buffer and reserve - // space for Ethernet-II header - skb_trim(ecd->tx_skb, 0); - skb_reserve(ecd->tx_skb, ETH_HLEN); - - // Copy data to socket buffer - frame_data = skb_put(ecd->tx_skb, length); - memcpy(frame_data, data, length); - - // Add Ethernet-II-Header - if (unlikely((eth = (struct ethhdr *) - skb_push(ecd->tx_skb, ETH_HLEN)) == NULL)) { - printk(KERN_ERR "EtherCAT: device_send -" - " Could not allocate Ethernet-II header!\n"); - return -1; - } - - // Protocol type - eth->h_proto = htons(0x88A4); - // Hardware address - memcpy(eth->h_source, ecd->dev->dev_addr, ecd->dev->addr_len); - // Broadcast address - memset(eth->h_dest, 0xFF, ecd->dev->addr_len); - - rdtscl(ecd->tx_time); // Get CPU cycles - - // Start sending of frame - ecd->state = EC_DEVICE_STATE_SENT; - ecd->dev->hard_start_xmit(ecd->tx_skb, ecd->dev); - - return 0; -} - -/*****************************************************************************/ - -/** - Holt einen empfangenen Rahmen von der Netzwerkkarte. - - Zuerst wird geprüft, ob überhaupt ein Rahmen empfangen - wurde. Wenn ja, wird dieser in den angegebenen - Speicherbereich kopiert. - - @param ecd EtherCAT-Gerät - @param data Zeiger auf den Speicherbereich, in den die - empfangenen Daten kopiert werden sollen +void ec_device_send(ec_device_t *ecd, /**< EtherCAT-Gerät */ + unsigned int length /**< Länge der zu sendenden Daten */ + ) +{ + struct ethhdr *eth; + + // Framegroesse auf (jetzt bekannte) Laenge abschneiden + skb_trim(ecd->tx_skb, length); + + // Ethernet-II-Header hinzufuegen + eth = (struct ethhdr *) skb_push(ecd->tx_skb, ETH_HLEN); + eth->h_proto = htons(0x88A4); + memcpy(eth->h_source, ecd->dev->dev_addr, ecd->dev->addr_len); + memset(eth->h_dest, 0xFF, ecd->dev->addr_len); + + ecd->state = EC_DEVICE_STATE_SENT; + ecd->rx_data_length = 0; + + // Senden einleiten + rdtscl(ecd->tx_time); // Get CPU cycles + ecd->dev->hard_start_xmit(ecd->tx_skb, ecd->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 *ecd) +{ + return ecd->rx_data_length; +} + +/*****************************************************************************/ + +/** + Gibt die empfangenen Daten zurück. + + \return Adresse auf empfangene Daten. +*/ + +uint8_t *ec_device_data(ec_device_t *ecd) +{ + return ecd->rx_data; +} + +/*****************************************************************************/ + +/** + Ruft die Interrupt-Routine der Netzwerkkarte auf. + + @param ecd EtherCAT-Gerät @return Anzahl der kopierten Bytes bei Erfolg, sonst < 0 */ -int ec_device_receive(ec_device_t *ecd, unsigned char *data) -{ - if (unlikely(ecd->state != EC_DEVICE_STATE_RECEIVED)) { - if (likely(ecd->error_reported)) { - printk(KERN_ERR "EtherCAT: receive - Nothing received!\n"); - ecd->error_reported = 1; - } - return -1; - } - - if (unlikely(ecd->rx_data_length > EC_FRAME_SIZE)) { - if (likely(ecd->error_reported)) { - printk(KERN_ERR "EtherCAT: receive - " - " Reveived frame is too long (%i Bytes)!\n", - ecd->rx_data_length); - ecd->error_reported = 1; - } - return -1; - } - - if (unlikely(ecd->error_reported)) { - ecd->error_reported = 0; - } - - memcpy(data, ecd->rx_data, ecd->rx_data_length); - - return ecd->rx_data_length; -} - -/*****************************************************************************/ - -/** - Ruft die Interrupt-Routine der Netzwerkkarte auf. - - @param ecd EtherCAT-Gerät - - @return Anzahl der kopierten Bytes bei Erfolg, sonst < 0 -*/ - void ec_device_call_isr(ec_device_t *ecd) { - if (likely(ecd->isr)) ecd->isr(0, ecd->dev, NULL); + if (likely(ecd->isr)) ecd->isr(0, ecd->dev, NULL); } /*****************************************************************************/ @@ -291,41 +246,33 @@ @param ecd EtherCAT-Gerät */ -void ec_device_debug(ec_device_t *ecd) -{ - printk(KERN_DEBUG "---EtherCAT device information begin---\n"); - - if (ecd) - { - printk(KERN_DEBUG "Assigned net_device: %X\n", - (unsigned) ecd->dev); - printk(KERN_DEBUG "Transmit socket buffer: %X\n", - (unsigned) ecd->tx_skb); - printk(KERN_DEBUG "Receive socket buffer: %X\n", - (unsigned) ecd->rx_skb); - printk(KERN_DEBUG "Time of last transmission: %u\n", - (unsigned) ecd->tx_time); - printk(KERN_DEBUG "Time of last receive: %u\n", - (unsigned) ecd->rx_time); - printk(KERN_DEBUG "Number of transmit interrupts: %u\n", - (unsigned) ecd->tx_intr_cnt); - printk(KERN_DEBUG "Number of receive interrupts: %u\n", - (unsigned) ecd->rx_intr_cnt); - printk(KERN_DEBUG "Total Number of interrupts: %u\n", - (unsigned) ecd->intr_cnt); - printk(KERN_DEBUG "Actual device state: %i\n", - (int) ecd->state); - printk(KERN_DEBUG "Receive buffer: %X\n", - (unsigned) ecd->rx_data); - printk(KERN_DEBUG "Receive buffer fill state: %u/%u\n", - (unsigned) ecd->rx_data_length, EC_FRAME_SIZE); - } - else - { - printk(KERN_DEBUG "Device is NULL!\n"); - } - - printk(KERN_DEBUG "---EtherCAT device information end---\n"); +void ec_device_print(ec_device_t *ecd) +{ + printk(KERN_DEBUG "---EtherCAT device information begin---\n"); + + if (ecd) + { + printk(KERN_DEBUG "Assigned net_device: %X\n", + (unsigned) ecd->dev); + printk(KERN_DEBUG "Transmit socket buffer: %X\n", + (unsigned) ecd->tx_skb); + printk(KERN_DEBUG "Time of last transmission: %u\n", + (unsigned) ecd->tx_time); + printk(KERN_DEBUG "Time of last receive: %u\n", + (unsigned) ecd->rx_time); + printk(KERN_DEBUG "Actual device state: %i\n", + (int) ecd->state); + printk(KERN_DEBUG "Receive buffer: %X\n", + (unsigned) ecd->rx_data); + printk(KERN_DEBUG "Receive buffer fill state: %u/%u\n", + (unsigned) ecd->rx_data_length, EC_MAX_FRAME_SIZE); + } + else + { + printk(KERN_DEBUG "Device is NULL!\n"); + } + + printk(KERN_DEBUG "---EtherCAT device information end---\n"); } /****************************************************************************** @@ -336,36 +283,24 @@ void EtherCAT_dev_state(ec_device_t *ecd, ec_device_state_t state) { - if (state == EC_DEVICE_STATE_TIMEOUT && ecd->state != EC_DEVICE_STATE_SENT) { - printk(KERN_WARNING "EtherCAT: Wrong status at timeout: %i\n", ecd->state); - } - - ecd->state = state; + ecd->state = state; } /*****************************************************************************/ int EtherCAT_dev_is_ec(ec_device_t *ecd, struct net_device *dev) { - return ecd && ecd->dev == dev; -} - -/*****************************************************************************/ - -int EtherCAT_dev_receive(ec_device_t *ecd, void *data, unsigned int size) -{ - if (ecd->state != EC_DEVICE_STATE_SENT) - { - printk(KERN_WARNING "EtherCAT: Received frame while not in SENT state!\n"); - return -1; - } - - // Copy received data to ethercat-device buffer, skip Ethernet-II header - memcpy(ecd->rx_data, data, size); - ecd->rx_data_length = size; - ecd->state = EC_DEVICE_STATE_RECEIVED; - - return 0; + return ecd && ecd->dev == dev; +} + +/*****************************************************************************/ + +void EtherCAT_dev_receive(ec_device_t *ecd, void *data, unsigned int size) +{ + // Copy received data to ethercat-device buffer + memcpy(ecd->rx_data, data, size); + ecd->rx_data_length = size; + ecd->state = EC_DEVICE_STATE_RECEIVED; } /*****************************************************************************/ @@ -378,6 +313,6 @@ /* Emacs-Konfiguration ;;; Local Variables: *** -;;; c-basic-offset:2 *** +;;; c-basic-offset:4 *** ;;; End: *** */ diff -r 7c986b717411 -r 9f4ea66d89a3 master/device.h --- a/master/device.h Wed Feb 22 17:36:28 2006 +0000 +++ b/master/device.h Thu Feb 23 09:58:50 2006 +0000 @@ -28,26 +28,19 @@ struct ec_device { - struct net_device *dev; /**< Zeiger auf das reservierte net_device */ - unsigned int open; /**< Das net_device ist geoeffnet. */ - struct sk_buff *tx_skb; /**< Zeiger auf Transmit-Socketbuffer */ - struct sk_buff *rx_skb; /**< Zeiger auf Receive-Socketbuffer */ - unsigned long tx_time; /**< Zeit des letzten Sendens */ - unsigned long rx_time; /**< Zeit des letzten Empfangs */ - unsigned long tx_intr_cnt; /**< Anzahl Tx-Interrupts */ - unsigned long rx_intr_cnt; /**< Anzahl Rx-Interrupts */ - unsigned long intr_cnt; /**< Anzahl Interrupts */ - volatile ec_device_state_t state; /**< Gesendet, Empfangen, - Timeout, etc. */ - unsigned char rx_data[EC_FRAME_SIZE]; /**< Puffer für - empfangene Rahmen */ - volatile unsigned int rx_data_length; /**< Länge des zuletzt - empfangenen Rahmens */ - irqreturn_t (*isr)(int, void *, struct pt_regs *); /**< Adresse der ISR */ - struct module *module; /**< Zeiger auf das Modul, das das Gerät zur - Verfügung stellt. */ - int error_reported; /**< Zeigt an, ob ein Fehler im zyklischen Code - bereits gemeldet wurde. */ + struct net_device *dev; /**< Zeiger auf das reservierte net_device */ + unsigned int 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 */ + volatile ec_device_state_t state; /**< Zustand des Gerätes */ + uint8_t rx_data[EC_MAX_FRAME_SIZE]; /**< Speicher für empfangene Rahmen */ + volatile unsigned int rx_data_length; /**< Länge des empfangenen Rahmens */ + irqreturn_t (*isr)(int, void *, struct pt_regs *); /**< Adresse der ISR */ + struct module *module; /**< Zeiger auf das Modul, das das Gerät zur + Verfügung stellt. */ + int error_reported; /**< Zeigt an, ob ein Fehler im zyklischen Code + bereits gemeldet wurde. */ }; /*****************************************************************************/ @@ -57,9 +50,17 @@ int ec_device_open(ec_device_t *); int ec_device_close(ec_device_t *); void ec_device_call_isr(ec_device_t *); -int ec_device_send(ec_device_t *, unsigned char *, unsigned int); -int ec_device_receive(ec_device_t *, unsigned char *); +uint8_t *ec_device_prepare(ec_device_t *); +void ec_device_send(ec_device_t *, unsigned int); +unsigned int ec_device_received(const ec_device_t *); +uint8_t *ec_device_data(ec_device_t *); /*****************************************************************************/ #endif + +/* Emacs-Konfiguration +;;; Local Variables: *** +;;; c-basic-offset:4 *** +;;; End: *** +*/ diff -r 7c986b717411 -r 9f4ea66d89a3 master/domain.c --- a/master/domain.c Wed Feb 22 17:36:28 2006 +0000 +++ b/master/domain.c Thu Feb 23 09:58:50 2006 +0000 @@ -8,33 +8,349 @@ * *****************************************************************************/ -#include - #include "globals.h" #include "domain.h" +#include "master.h" /*****************************************************************************/ /** Konstruktor einer EtherCAT-Domäne. - - @param dom Zeiger auf die zu initialisierende Domäne -*/ - -void ec_domain_init(ec_domain_t *dom) -{ - dom->number = -1; - dom->data_size = 0; - dom->logical_offset = 0; - dom->response_count = 0xFFFFFFFF; - - memset(dom->data, 0x00, EC_FRAME_SIZE); -} +*/ + +void ec_domain_init(ec_domain_t *domain, /**< Domäne */ + ec_master_t *master, /**< Zugehöriger Master */ + ec_domain_mode_t mode, /**< Synchron/Asynchron */ + unsigned int timeout_us /**< Timeout in Mikrosekunden */ + ) +{ + domain->master = master; + domain->mode = mode; + domain->timeout_us = timeout_us; + + domain->data = NULL; + domain->data_size = 0; + domain->base_address = 0; + domain->response_count = 0xFFFFFFFF; + + INIT_LIST_HEAD(&domain->field_regs); +} + +/*****************************************************************************/ + +/** + Destruktor einer EtherCAT-Domäne. +*/ + +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); + } +} + +/*****************************************************************************/ + +/** + Registriert ein Feld in einer Domäne. + + \returns 0 bei Erfolg, < 0 bei Fehler +*/ + +int ec_domain_reg_field(ec_domain_t *domain, /**< Domäne */ + ec_slave_t *slave, /**< Slave */ + const ec_sync_t *sync, /**< Sync-Manager */ + uint32_t field_offset, /**< Datenfeld-Offset */ + void **data_ptr /**< Adresse des Prozessdatenzeigers */ + ) +{ + ec_field_reg_t *field_reg; + + if (!(field_reg = (ec_field_reg_t *) kmalloc(sizeof(ec_field_reg_t), + GFP_KERNEL))) { + printk(KERN_ERR "EtherCAT: Failed to allocate field registration.\n"); + return -1; + } + + if (ec_slave_set_fmmu(slave, domain, sync)) { + printk(KERN_ERR "EtherCAT: FMMU configuration failed.\n"); + kfree(field_reg); + return -1; + } + + field_reg->slave = slave; + field_reg->sync = sync; + field_reg->field_offset = field_offset; + field_reg->data_ptr = data_ptr; + + list_add_tail(&field_reg->list, &domain->field_regs); + + return 0; +} + +/*****************************************************************************/ + +/** + \returns 0 bei Erfolg, < 0 bei Fehler +*/ + +int ec_domain_alloc(ec_domain_t *domain, /**< Domäne */ + uint32_t base_address /**< Logische Basisadresse */ + ) +{ + ec_field_reg_t *field_reg, *next; + ec_slave_t *slave; + ec_fmmu_t *fmmu; + unsigned int i, j, found, data_offset; + + if (domain->data) { + printk(KERN_ERR "EtherCAT: Domain already allocated!\n"); + return -1; + } + + domain->base_address = base_address; + + // Größe der Prozessdaten berechnen + // und logische Adressen der FMMUs setzen + domain->data_size = 0; + for (i = 0; i < domain->master->slave_count; i++) { + slave = &domain->master->slaves[i]; + for (j = 0; j < slave->fmmu_count; j++) { + fmmu = &slave->fmmus[j]; + if (fmmu->domain == domain) { + fmmu->logical_start_address = base_address + domain->data_size; + domain->data_size += fmmu->sync->size; + } + } + } + + if (!domain->data_size) { + printk(KERN_WARNING "EtherCAT: Domain 0x%08X contains no data!\n", + (u32) domain); + } + else { + // Prozessdaten allozieren + if (!(domain->data = kmalloc(domain->data_size, GFP_KERNEL))) { + printk(KERN_ERR "EtherCAT: 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 + printk(KERN_ERR "EtherCAT: 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! + + return 0; +} + +/****************************************************************************** + * + * Echtzeitschnittstelle + * + *****************************************************************************/ + +/** + Registriert einer Domäne ein Datenfeld hinzu. + + \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 *slave; + const ec_slave_type_t *type; + ec_master_t *master; + const ec_sync_t *sync; + const ec_field_t *field; + unsigned int field_idx, found, i, j; + uint32_t field_offset; + + if (!field_count) { + printk(KERN_ERR "EtherCAT: field_count may not be 0!\n"); + return NULL; + } + + master = domain->master; + + // Adresse übersetzen + if ((slave = ec_address(master, address)) == NULL) return NULL; + + if (!(type = slave->type)) { + printk(KERN_ERR "EtherCAT: Slave \"%s\" (position %i) has unknown" + " type!\n", address, slave->ring_position); + return NULL; + } + + if (strcmp(vendor_name, type->vendor_name) || + strcmp(product_name, type->product_name)) { + printk(KERN_ERR "EtherCAT: Invalid slave type at position %i -" + " Requested: \"%s %s\", found: \"%s %s\".\n", + slave->ring_position, vendor_name, product_name, + type->vendor_name, type->product_name); + return NULL; + } + + field_idx = 0; + found = 0; + for (i = 0; type->sync_managers[i] && !found; i++) { + sync = type->sync_managers[i]; + field_offset = 0; + for (j = 0; sync->fields[j]; j++) { + field = sync->fields[j]; + if (field->type == field_type) { + if (field_idx == field_index) { + ec_domain_reg_field(domain, slave, sync, field_offset, + data_ptr++); + if (!(--field_count)) return slave; + } + field_idx++; + } + field_offset += field->size; + } + } + + printk(KERN_ERR "EtherCAT: Slave %i (\"%s %s\") has less than %i fields of" + " type %i, starting at %i!\n", slave->ring_position, + vendor_name, product_name, field_count, field_type, field_index); + return NULL; +} + +/*****************************************************************************/ + +/** + Sendet und empfängt Prozessdaten der angegebenen Domäne + + \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_output_lost_frames(master); // Evtl. verlorene Frames ausgeben + + rdtscl(start_ticks); // Sendezeit nehmen + timeout_ticks = domain->timeout_us * cpu_khz / 1000; + + offset = 0; + while (offset < domain->data_size) + { + 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)) { + printk(KERN_ERR "EtherCAT: Could not send process data" + " command!\n"); + 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)) { + master->device.state = EC_DEVICE_STATE_READY; + master->frames_lost++; + ec_output_lost_frames(master); + return -1; + } + + if (unlikely(ec_frame_receive(frame) < 0)) { + printk(KERN_ERR "EtherCAT: Receive error!\n"); + return -1; + } + + if (unlikely(frame->state != ec_frame_received)) { + printk(KERN_WARNING "EtherCAT: Process data command not" + " received!\n"); + return -1; + } + + working_counter_sum += frame->working_counter; + + // Daten vom Rahmen in den Prozessdatenspeicher kopieren + memcpy(domain->data + offset, frame->data, size); + + offset += size; + } + + if (working_counter_sum != domain->response_count) { + domain->response_count = working_counter_sum; + printk(KERN_INFO "EtherCAT: Domain %08X state change - %i slaves" + " responding.\n", (unsigned int) domain, working_counter_sum); + } + + return 0; +} + +/*****************************************************************************/ + +EXPORT_SYMBOL(EtherCAT_rt_register_slave_field); +EXPORT_SYMBOL(EtherCAT_rt_domain_xio); /*****************************************************************************/ /* Emacs-Konfiguration ;;; Local Variables: *** -;;; c-basic-offset:2 *** +;;; c-basic-offset:4 *** ;;; End: *** */ diff -r 7c986b717411 -r 9f4ea66d89a3 master/domain.h --- a/master/domain.h Wed Feb 22 17:36:28 2006 +0000 +++ b/master/domain.h Thu Feb 23 09:58:50 2006 +0000 @@ -11,9 +11,27 @@ #ifndef _EC_DOMAIN_H_ #define _EC_DOMAIN_H_ +#include + #include "globals.h" #include "slave.h" -#include "command.h" +#include "frame.h" + +/*****************************************************************************/ + +/** + Datenfeld-Konfiguration. +*/ + +typedef struct +{ + struct list_head list; + ec_slave_t *slave; + const ec_sync_t *sync; + uint32_t field_offset; + void **data_ptr; +} +ec_field_reg_t; /*****************************************************************************/ @@ -24,28 +42,37 @@ Menge von Slaves. */ -typedef struct ec_domain +struct ec_domain { - int number; /*<< Domänen-Identifikation */ - ec_command_t command; /**< Kommando zum Senden und Empfangen der - Prozessdaten */ - unsigned char data[EC_FRAME_SIZE]; /**< Prozessdaten-Array */ - unsigned int data_size; /**< Größe der Prozessdaten */ - unsigned int logical_offset; /**< Logische Basisaddresse */ - unsigned int response_count; /**< Anzahl antwortender Slaves */ -} -ec_domain_t; + 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 */ + + 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 */ +}; /*****************************************************************************/ -void ec_domain_init(ec_domain_t *); +void ec_domain_init(ec_domain_t *, ec_master_t *, ec_domain_mode_t, + unsigned int); +void ec_domain_clear(ec_domain_t *); + +int ec_domain_alloc(ec_domain_t *, uint32_t); /*****************************************************************************/ #endif /* Emacs-Konfiguration -;;; Local Variables: *** -;;; c-basic-offset:2 *** + ;;; Local Variables: *** + ;;; c-basic-offset:4 *** ;;; End: *** */ diff -r 7c986b717411 -r 9f4ea66d89a3 master/frame.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/master/frame.c Thu Feb 23 09:58:50 2006 +0000 @@ -0,0 +1,494 @@ +/****************************************************************************** + * + * f r a m e . c + * + * Methoden für einen EtherCAT-Frame. + * + * $Id$ + * + *****************************************************************************/ + +#include +#include + +#include "frame.h" +#include "master.h" + +/*****************************************************************************/ + +#define EC_FUNC_HEADER \ + frame->master = master; \ + frame->state = ec_frame_ready; \ + 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; + +/*****************************************************************************/ + +/** + 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)) + printk(KERN_WARNING "EtherCAT: Warning - 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)) + printk(KERN_WARNING "EtherCAT: Warning - 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->debug_level > 0)) { + printk(KERN_DEBUG "EtherCAT: ec_frame_send\n"); + } + + if (unlikely(frame->state != ec_frame_ready)) { + printk(KERN_WARNING "EtherCAT: Frame not in \"ready\" state!\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)) { + printk(KERN_ERR "EtherCAT: 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)) { + printk(KERN_DEBUG "EtherCAT: 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)) { + printk(KERN_DEBUG "EtherCAT: Sending command index 0x%X\n", + frame->index); + } + + frame->state = ec_frame_sent; + + // Zeiger auf Socket-Buffer holen + data = ec_device_prepare(&frame->master->device); + + // EtherCAT frame header + data[0] = command_size & 0xFF; + data[1] = ((command_size & 0x700) >> 8) | 0x10; + data += EC_FRAME_HEADER_SIZE; + + // EtherCAT command header + data[0] = frame->type; + data[1] = frame->index; + data[2] = frame->address.raw[0]; + data[3] = frame->address.raw[1]; + data[4] = frame->address.raw[2]; + data[5] = frame->address.raw[3]; + data[6] = frame->data_length & 0xFF; + data[7] = (frame->data_length & 0x700) >> 8; + data[8] = 0x00; + data[9] = 0x00; + data += EC_COMMAND_HEADER_SIZE; + + if (likely(frame->type == ec_frame_type_apwr // Write commands + || frame->type == ec_frame_type_npwr + || frame->type == ec_frame_type_bwr + || frame->type == ec_frame_type_lrw)) { + memcpy(data, frame->data, frame->data_length); + } + else { // Read commands + memset(data, 0x00, frame->data_length); + } + + // EtherCAT command footer + data += frame->data_length; + data[0] = frame->working_counter & 0xFF; + data[1] = (frame->working_counter & 0xFF00) >> 8; + 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++) { + *data++ = 0x00; + } + + // Send frame + ec_device_send(&frame->master->device, frame_size); + + return 0; +} + +/*****************************************************************************/ + +/** + Empfängt einen gesendeten Rahmen. + + \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; + + if (unlikely(frame->state != ec_frame_sent)) { + printk(KERN_ERR "EtherCAT: Frame was not sent!\n"); + return -1; + } + + 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)) { + printk(KERN_ERR "EtherCAT: Received frame with incomplete EtherCAT" + " frame header!\n"); + ec_frame_print(frame); + return -1; + } + + data = ec_device_data(device); + + // Länge des gesamten Frames prüfen + frame_length = (data[0] & 0xFF) | ((data[1] & 0x07) << 8); + + if (unlikely(frame_length > received_length)) { + printk(KERN_ERR "EtherCAT: Received corrupted frame (length does" + " not match)!\n"); + ec_frame_print(frame); + return -1; + } + + // Command header + data += EC_FRAME_HEADER_SIZE; + command_type = data[0]; + command_index = data[1]; + data_length = (data[6] & 0xFF) | ((data[7] & 0x07) << 8); + + if (unlikely(EC_FRAME_HEADER_SIZE + EC_COMMAND_HEADER_SIZE + + data_length + EC_COMMAND_FOOTER_SIZE > received_length)) { + printk(KERN_ERR "EtherCAT: Received frame with incomplete command" + " data!\n"); + ec_frame_print(frame); + return -1; + } + + if (unlikely(frame->type != command_type + || frame->index != command_index + || frame->data_length != data_length)) + { + printk(KERN_WARNING "EtherCAT: WARNING - Send/Receive anomaly!\n"); + ec_frame_print(frame); + ec_device_call_isr(device); // Empfangenes "vergessen" + return -1; + } + + frame->state = ec_frame_received; + + // Empfangene Daten in Kommandodatenspeicher kopieren + data += EC_COMMAND_HEADER_SIZE; + memcpy(frame->data, data, data_length); + data += data_length; + + // Working-Counter setzen + frame->working_counter = (data[0] & 0xFF) | ((data[1] & 0xFF) << 8); + + if (unlikely(frame->master->debug_level > 1)) { + ec_frame_print(frame); + } + + return 0; +} + +/*****************************************************************************/ + +/** + Sendet einen einzeln Rahmen und wartet auf dessen Empfang. + + \return 0 bei Erfolg, sonst < 0 +*/ + +int ec_frame_send_receive(ec_frame_t *frame + /**< Rahmen zum Senden/Empfangen */ + ) +{ + unsigned int tries_left; + + if (unlikely(ec_frame_send(frame) < 0)) { + printk(KERN_ERR "EtherCAT: Frame sending failed!\n"); + return -1; + } + + tries_left = 20; + do + { + udelay(1); + ec_device_call_isr(&frame->master->device); + tries_left--; + } + while (unlikely(!ec_device_received(&frame->master->device) + && tries_left)); + + if (unlikely(!tries_left)) { + printk(KERN_ERR "EtherCAT: Frame timeout!\n"); + return -1; + } + + if (unlikely(ec_frame_receive(frame) < 0)) { + printk(KERN_ERR "EtherCAT: Frame receiving failed!\n"); + return -1; + } + + return 0; +} + +/*****************************************************************************/ + +/** + Gibt Frame-Inhalte zwecks Debugging aus. +*/ + +void ec_frame_print(const ec_frame_t *frame /**< EtherCAT-Frame */) +{ + unsigned int i; + + printk(KERN_DEBUG "EtherCAT: Frame contents (%i Bytes):\n", + frame->data_length); + + printk(KERN_DEBUG); + for (i = 0; i < frame->data_length; i++) + { + printk("%02X ", frame->data[i]); + if ((i + 1) % 16 == 0) printk("\n" KERN_DEBUG); + } + printk("\n"); +} + +/*****************************************************************************/ + +/* Emacs-Konfiguration +;;; Local Variables: *** +;;; c-basic-offset:4 *** +;;; End: *** +*/ diff -r 7c986b717411 -r 9f4ea66d89a3 master/frame.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/master/frame.h Thu Feb 23 09:58:50 2006 +0000 @@ -0,0 +1,132 @@ +/****************************************************************************** + * + * 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" + +/*****************************************************************************/ + +#define EC_MAX_DATA_SIZE (EC_MAX_FRAME_SIZE - EC_FRAME_HEADER_SIZE \ + - EC_COMMAND_HEADER_SIZE \ + - EC_COMMAND_FOOTER_SIZE) + +/*****************************************************************************/ + +/** + Status eines EtherCAT-Rahmens. +*/ + +typedef enum { + ec_frame_ready, ec_frame_sent, ec_frame_received +} +ec_frame_state_t; + +/*****************************************************************************/ + +/** + 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 */ + uint16_t mem; /**< Physikalische Speicheradresse im Slave */ + } + physical; /**< Physikalische Adresse */ + + uint32_t logical; /**< Logische Adresse */ + uint8_t raw[4]; /**< Rohdaten für die Generierung des Frames */ +} +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 */ + ec_frame_state_t state; /**< Zustand des Kommandos */ + 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 *); + +void ec_frame_print(const ec_frame_t *); + +/*****************************************************************************/ + +#endif + +/* Emacs-Konfiguration +;;; Local Variables: *** +;;; c-basic-offset:4 *** +;;; End: *** +*/ diff -r 7c986b717411 -r 9f4ea66d89a3 master/globals.h --- a/master/globals.h Wed Feb 22 17:36:28 2006 +0000 +++ b/master/globals.h Thu Feb 23 09:58:50 2006 +0000 @@ -13,65 +13,51 @@ /*****************************************************************************/ -/** - Maximale Größe eines EtherCAT-Frames -*/ -#define EC_FRAME_SIZE 1500 +// EtherCAT-Protokoll +#define EC_MAX_FRAME_SIZE 1500 /**< Maximale Größe eines EtherCAT-Frames ohne + 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 */ +#define EC_COMMAND_FOOTER_SIZE 2 /**< Größe eines EtherCAT-Kommando-Footers */ +#define EC_SYNC_SIZE 8 /**< Größe einer Sync-Manager-Konfigurationsseite */ +#define EC_FMMU_SIZE 16 /**< Größe einer FMMU-Konfigurationsseite */ +#define EC_MAX_FMMUS 16 /**< Maximale Anzahl FMMUs pro Slave */ -/** - Maximale Anzahl der Prozessdatendomänen in einem Master -*/ -#define EC_MAX_DOMAINS 10 - -/** - NULL-Define, falls noch nicht definiert. -*/ +#define EC_MASTER_MAX_DOMAINS 10 /**< Maximale Anzahl Domänen eines Masters */ #ifndef NULL -#define NULL ((void *) 0) +#define NULL ((void *) 0) /**< NULL-Define, falls noch nicht definiert. */ #endif /*****************************************************************************/ /** - EtherCAT-Kommando-Typ -*/ - -typedef enum -{ - EC_COMMAND_NONE = 0x00, /**< Dummy */ - EC_COMMAND_APRD = 0x01, /**< Auto-increment physical read */ - EC_COMMAND_APWR = 0x02, /**< Auto-increment physical write */ - EC_COMMAND_NPRD = 0x04, /**< Node-addressed physical read */ - EC_COMMAND_NPWR = 0x05, /**< Node-addressed physical write */ - EC_COMMAND_BRD = 0x07, /**< Broadcast read */ - EC_COMMAND_BWR = 0x08, /**< Broadcast write */ - EC_COMMAND_LRW = 0x0C /**< Logical read/write */ -} -ec_command_type_t; - -/*****************************************************************************/ - -/** 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_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 +;;; Local Variables: *** +;;; c-basic-offset:4 *** +;;; End: *** +*/ diff -r 7c986b717411 -r 9f4ea66d89a3 master/master.c --- a/master/master.c Wed Feb 22 17:36:28 2006 +0000 +++ b/master/master.c Thu Feb 23 09:58:50 2006 +0000 @@ -20,17 +20,7 @@ #include "slave.h" #include "types.h" #include "device.h" -#include "command.h" - -/*****************************************************************************/ - -// Prototypen - -int ec_simple_send(ec_master_t *, ec_command_t *); -int ec_simple_receive(ec_master_t *, ec_command_t *); -void ec_output_debug_data(const ec_master_t *); -int ec_sii_read(ec_master_t *, unsigned short, unsigned short, unsigned int *); -void ec_output_lost_frames(ec_master_t *); +#include "frame.h" /*****************************************************************************/ @@ -38,21 +28,17 @@ Konstruktor des EtherCAT-Masters. */ -void ec_master_init(ec_master_t *master - /**< Zeiger auf den zu initialisierenden EtherCAT-Master */ - ) -{ - master->bus_slaves = NULL; - master->bus_slaves_count = 0; - master->device_registered = 0; - master->command_index = 0x00; - master->tx_data_length = 0; - master->rx_data_length = 0; - master->domain_count = 0; - master->debug_level = 0; - master->bus_time = 0; - master->frames_lost = 0; - master->t_lost_output = 0; +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->domain_count = 0; + master->debug_level = 0; + master->bus_time = 0; + master->frames_lost = 0; + master->t_lost_output = 0; } /*****************************************************************************/ @@ -64,24 +50,16 @@ auf das Slave-Array und gibt die Prozessdaten frei. */ -void ec_master_clear(ec_master_t *master - /**< Zeiger auf den zu löschenden Master */ - ) -{ - if (master->bus_slaves) { - kfree(master->bus_slaves); - master->bus_slaves = NULL; - } - - ec_device_clear(&master->device); - - master->domain_count = 0; -} - -/*****************************************************************************/ - -/** - Setzt den Master in den Ausgangszustand. +void ec_master_clear(ec_master_t *master /**< EtherCAT-Master */) +{ + ec_master_reset(master); + ec_device_clear(&master->device); +} + +/*****************************************************************************/ + +/** + Setzt den Master zurück in den Ausgangszustand. Bei einem "release" sollte immer diese Funktion aufgerufen werden, da sonst Slave-Liste, Domains, etc. weiter existieren. @@ -91,20 +69,28 @@ /**< Zeiger auf den zurückzusetzenden Master */ ) { - if (master->bus_slaves) { - kfree(master->bus_slaves); - master->bus_slaves = NULL; - } - - master->bus_slaves_count = 0; - master->command_index = 0; - master->tx_data_length = 0; - master->rx_data_length = 0; - master->domain_count = 0; - master->debug_level = 0; - master->bus_time = 0; - master->frames_lost = 0; - master->t_lost_output = 0; + unsigned int i; + + if (master->slaves) { + for (i = 0; i < master->slave_count; i++) { + ec_slave_clear(master->slaves + i); + } + kfree(master->slaves); + master->slaves = NULL; + } + master->slave_count = 0; + + for (i = 0; i < master->domain_count; i++) { + ec_domain_clear(master->domains[i]); + kfree(master->domains[i]); + } + master->domain_count = 0; + + master->command_index = 0; + master->debug_level = 0; + master->bus_time = 0; + master->frames_lost = 0; + master->t_lost_output = 0; } /*****************************************************************************/ @@ -118,17 +104,17 @@ int ec_master_open(ec_master_t *master /**< Der EtherCAT-Master */) { - if (!master->device_registered) { - printk(KERN_ERR "EtherCAT: No device registered!\n"); - return -1; - } - - if (ec_device_open(&master->device) < 0) { - printk(KERN_ERR "EtherCAT: Could not open device!\n"); - return -1; - } - - return 0; + if (!master->device_registered) { + printk(KERN_ERR "EtherCAT: No device registered!\n"); + return -1; + } + + if (ec_device_open(&master->device) < 0) { + printk(KERN_ERR "EtherCAT: Could not open device!\n"); + return -1; + } + + return 0; } /*****************************************************************************/ @@ -139,232 +125,15 @@ void ec_master_close(ec_master_t *master /**< EtherCAT-Master */) { - if (!master->device_registered) { - printk(KERN_WARNING "EtherCAT: Warning -" - " Trying to close an unregistered device!\n"); - return; - } - - if (ec_device_close(&master->device) < 0) { - printk(KERN_WARNING "EtherCAT: Warning - Could not close device!\n"); - } -} - -/*****************************************************************************/ - -/** - Sendet ein einzelnes Kommando in einem Frame und - wartet auf dessen Empfang. - - \return 0 bei Erfolg, sonst < 0 -*/ - -int ec_simple_send_receive(ec_master_t *master, - /**< EtherCAT-Master */ - ec_command_t *cmd - /**< Kommando zum Senden/Empfangen */ - ) -{ - unsigned int tries_left; - - if (unlikely(ec_simple_send(master, cmd) < 0)) - return -1; - - tries_left = 20; - - do - { - udelay(1); - ec_device_call_isr(&master->device); - tries_left--; - } - while (unlikely(master->device.state == EC_DEVICE_STATE_SENT && tries_left)); - - if (unlikely(ec_simple_receive(master, cmd) < 0)) - return -1; - - return 0; -} - -/*****************************************************************************/ - -/** - Sendet ein einzelnes Kommando in einem Frame. - - \return 0 bei Erfolg, sonst < 0 -*/ - -int ec_simple_send(ec_master_t *master, /**< EtherCAT-Master */ - ec_command_t *cmd /**< Kommando zum Senden */ - ) -{ - unsigned int length, framelength, i; - - if (unlikely(master->debug_level > 0)) { - printk(KERN_DEBUG "EtherCAT: ec_simple_send\n"); - } - - if (unlikely(cmd->state != EC_COMMAND_STATE_READY)) { - printk(KERN_WARNING "EtherCAT: cmd not in ready state!\n"); - } - - length = cmd->data_length + 12; - framelength = length + 2; - - if (unlikely(framelength > EC_FRAME_SIZE)) { - printk(KERN_ERR "EtherCAT: Frame too long (%i)!\n", framelength); - return -1; - } - - if (framelength < 46) framelength = 46; - - if (unlikely(master->debug_level > 0)) { - printk(KERN_DEBUG "EtherCAT: Frame length: %i\n", framelength); - } - - master->tx_data[0] = length & 0xFF; - master->tx_data[1] = ((length & 0x700) >> 8) | 0x10; - - cmd->index = master->command_index; - master->command_index = (master->command_index + 1) % 0x0100; - - if (unlikely(master->debug_level > 0)) { - printk(KERN_DEBUG "EtherCAT: Sending command index 0x%X\n", cmd->index); - } - - cmd->state = EC_COMMAND_STATE_SENT; - - master->tx_data[2 + 0] = cmd->type; - master->tx_data[2 + 1] = cmd->index; - master->tx_data[2 + 2] = cmd->address.raw[0]; - master->tx_data[2 + 3] = cmd->address.raw[1]; - master->tx_data[2 + 4] = cmd->address.raw[2]; - master->tx_data[2 + 5] = cmd->address.raw[3]; - master->tx_data[2 + 6] = cmd->data_length & 0xFF; - master->tx_data[2 + 7] = (cmd->data_length & 0x700) >> 8; - master->tx_data[2 + 8] = 0x00; - master->tx_data[2 + 9] = 0x00; - - if (likely(cmd->type == EC_COMMAND_APWR - || cmd->type == EC_COMMAND_NPWR - || cmd->type == EC_COMMAND_BWR - || cmd->type == EC_COMMAND_LRW)) // Write commands - { - for (i = 0; i < cmd->data_length; i++) - master->tx_data[2 + 10 + i] = cmd->data[i]; - } - else // Read commands - { - for (i = 0; i < cmd->data_length; i++) master->tx_data[2 + 10 + i] = 0x00; - } - - master->tx_data[2 + 10 + cmd->data_length] = 0x00; - master->tx_data[2 + 11 + cmd->data_length] = 0x00; - - // Pad with zeros - for (i = cmd->data_length + 12 + 2; i < 46; i++) master->tx_data[i] = 0x00; - - master->tx_data_length = framelength; - - if (unlikely(master->debug_level > 0)) { - printk(KERN_DEBUG "EtherCAT: Device send...\n"); - } - - // Send frame - if (unlikely(ec_device_send(&master->device, master->tx_data, - framelength) != 0)) { - printk(KERN_ERR "EtherCAT: Could not send!\n"); - return -1; - } - - if (unlikely(master->debug_level > 0)) { - printk(KERN_DEBUG "EtherCAT: ec_simple_send done.\n"); - } - - return 0; -} - -/*****************************************************************************/ - -/** - Wartet auf den Empfang eines einzeln gesendeten - Kommandos. - - \return 0 bei Erfolg, sonst < 0 -*/ - -int ec_simple_receive(ec_master_t *master, /**< EtherCAT-Master */ - ec_command_t *cmd /**< Gesendetes Kommando */ - ) -{ - unsigned int length; - int ret; - unsigned char command_type, command_index; - - if (unlikely((ret = ec_device_receive(&master->device, - master->rx_data)) < 0)) - return -1; - - master->rx_data_length = (unsigned int) ret; - - if (unlikely(master->rx_data_length < 2)) { - printk(KERN_ERR "EtherCAT: Received frame with incomplete EtherCAT" - " header!\n"); - ec_output_debug_data(master); - return -1; - } - - // Länge des gesamten Frames prüfen - length = ((master->rx_data[1] & 0x07) << 8) - | (master->rx_data[0] & 0xFF); - - if (unlikely(length > master->rx_data_length)) { - printk(KERN_ERR "EtherCAT: Received corrupted frame (length does" - " not match)!\n"); - ec_output_debug_data(master); - return -1; - } - - command_type = master->rx_data[2]; - command_index = master->rx_data[2 + 1]; - length = (master->rx_data[2 + 6] & 0xFF) - | ((master->rx_data[2 + 7] & 0x07) << 8); - - if (unlikely(master->rx_data_length - 2 < length + 12)) { - printk(KERN_ERR "EtherCAT: Received frame with" - " incomplete command data!\n"); - ec_output_debug_data(master); - return -1; - } - - if (likely(cmd->state == EC_COMMAND_STATE_SENT - && cmd->type == command_type - && cmd->index == command_index - && cmd->data_length == length)) - { - cmd->state = EC_COMMAND_STATE_RECEIVED; - - // Empfangene Daten in Kommandodatenspeicher kopieren - memcpy(cmd->data, master->rx_data + 2 + 10, length); - - // Working-Counter setzen - cmd->working_counter - = ((master->rx_data[length + 2 + 10] & 0xFF) - | ((master->rx_data[length + 2 + 11] & 0xFF) << 8)); - - if (unlikely(master->debug_level > 1)) { - ec_output_debug_data(master); - } - } - else - { - printk(KERN_WARNING "EtherCAT: WARNING - Send/Receive anomaly!\n"); - ec_output_debug_data(master); - } - - master->device.state = EC_DEVICE_STATE_READY; - - return 0; + if (!master->device_registered) { + printk(KERN_WARNING "EtherCAT: Warning -" + " Trying to close an unregistered device!\n"); + return; + } + + if (ec_device_close(&master->device) < 0) { + printk(KERN_WARNING "EtherCAT: Warning - Could not close device!\n"); + } } /*****************************************************************************/ @@ -377,319 +146,86 @@ int ec_scan_for_slaves(ec_master_t *master /**< EtherCAT-Master */) { - ec_command_t cmd; - ec_slave_t *slave; - unsigned int i, j; - unsigned char data[2]; - - // Determine number of slaves on bus - - ec_command_broadcast_read(&cmd, 0x0000, 4); - - if (unlikely(ec_simple_send_receive(master, &cmd) < 0)) - return -1; - - master->bus_slaves_count = cmd.working_counter; - printk("EtherCAT: Found %i slaves on bus.\n", master->bus_slaves_count); - - if (!master->bus_slaves_count) return 0; - - if (!(master->bus_slaves = (ec_slave_t *) kmalloc(master->bus_slaves_count - * sizeof(ec_slave_t), - GFP_KERNEL))) { - printk(KERN_ERR "EtherCAT: Could not allocate memory for bus slaves!\n"); - return -1; - } - - // For every slave in the list - for (i = 0; i < master->bus_slaves_count; i++) - { - slave = master->bus_slaves + i; - - ec_slave_init(slave); - - // Set ring position - - slave->ring_position = -i; - slave->station_address = i + 1; - - // Write station address - - data[0] = slave->station_address & 0x00FF; - data[1] = (slave->station_address & 0xFF00) >> 8; - - ec_command_position_write(&cmd, slave->ring_position, 0x0010, 2, data); - - if (unlikely(ec_simple_send_receive(master, &cmd) < 0)) - return -1; - - if (unlikely(cmd.working_counter != 1)) { - printk(KERN_ERR "EtherCAT: Slave %i did not repond while writing" - " station address!\n", i); - return -1; - } - - // Read base data - - ec_command_read(&cmd, slave->station_address, 0x0000, 4); - - if (unlikely(ec_simple_send_receive(master, &cmd) < 0)) - return -1; - - if (unlikely(cmd.working_counter != 1)) { - printk(KERN_ERR "EtherCAT: Slave %i did not respond while reading base" - " data!\n", i); - return -1; - } - - // Get base data - - slave->base_type = cmd.data[0]; - slave->base_revision = cmd.data[1]; - slave->base_build = cmd.data[2] | (cmd.data[3] << 8); - - // Read identification from "Slave Information Interface" (SII) - - if (unlikely(ec_sii_read(master, slave->station_address, 0x0008, - &slave->sii_vendor_id) != 0)) { - printk(KERN_ERR "EtherCAT: Could not read SII vendor id!\n"); - return -1; - } - - if (unlikely(ec_sii_read(master, slave->station_address, 0x000A, - &slave->sii_product_code) != 0)) { - printk(KERN_ERR "EtherCAT: Could not read SII product code!\n"); - return -1; - } - - if (unlikely(ec_sii_read(master, slave->station_address, 0x000C, - &slave->sii_revision_number) != 0)) { - printk(KERN_ERR "EtherCAT: Could not read SII revision number!\n"); - return -1; - } - - if (unlikely(ec_sii_read(master, slave->station_address, 0x000E, - &slave->sii_serial_number) != 0)) { - printk(KERN_ERR "EtherCAT: Could not read SII serial number!\n"); - return -1; - } - - // Search for identification in "database" - - for (j = 0; j < slave_ident_count; j++) + ec_frame_t frame; + ec_slave_t *slave; + ec_slave_ident_t *ident; + unsigned int i; + unsigned char data[2]; + + if (master->slaves || master->slave_count) { + printk(KERN_ERR "EtherCAT: Slave scan already done!\n"); + return -1; + } + + // Determine number of slaves on bus + + ec_frame_init_brd(&frame, master, 0x0000, 4); + if (unlikely(ec_frame_send_receive(&frame) < 0)) return -1; + + master->slave_count = frame.working_counter; + printk("EtherCAT: Found %i slaves on bus.\n", master->slave_count); + + if (!master->slave_count) return 0; + + if (!(master->slaves = (ec_slave_t *) kmalloc(master->slave_count + * sizeof(ec_slave_t), + GFP_KERNEL))) { + printk(KERN_ERR "EtherCAT: Could not allocate memory for bus" + " slaves!\n"); + return -1; + } + + // Init slaves + for (i = 0; i < master->slave_count; i++) { + slave = master->slaves + i; + ec_slave_init(slave, master); + slave->ring_position = i; + slave->station_address = i + 1; + } + + // For every slave in the list + for (i = 0; i < master->slave_count; i++) { - if (unlikely(slave_idents[j].vendor_id == slave->sii_vendor_id - && slave_idents[j].product_code == slave->sii_product_code)) - { - slave->type = slave_idents[j].type; - break; - } - } - - if (unlikely(!slave->type)) { - printk(KERN_WARNING "EtherCAT: Unknown slave device (vendor 0x%08X, code" - " 0x%08X) at position %i.\n", slave->sii_vendor_id, - slave->sii_product_code, i); - return 0; - } - } - - return 0; -} - -/*****************************************************************************/ - -/** - Liest Daten aus dem Slave-Information-Interface - eines EtherCAT-Slaves. - - \return 0 bei Erfolg, sonst < 0 -*/ - -int ec_sii_read(ec_master_t *master, - /**< EtherCAT-Master */ - unsigned short int node_address, - /**< Knotenadresse des Slaves */ - unsigned short int offset, - /**< Adresse des zu lesenden SII-Registers */ - unsigned int *target - /**< Zeiger auf einen 4 Byte großen Speicher zum Ablegen der - Daten */ - ) -{ - ec_command_t cmd; - unsigned char data[10]; - unsigned int tries_left; - - // Initiate read operation - - data[0] = 0x00; - data[1] = 0x01; - data[2] = offset & 0xFF; - data[3] = (offset & 0xFF00) >> 8; - data[4] = 0x00; - data[5] = 0x00; - - ec_command_write(&cmd, node_address, 0x502, 6, data); - - if (unlikely(ec_simple_send_receive(master, &cmd) < 0)) - return -1; - - if (unlikely(cmd.working_counter != 1)) { - printk(KERN_ERR "EtherCAT: SII-read - Slave %04X did not respond!\n", - node_address); - return -1; - } - - // Der Slave legt die Informationen des Slave-Information-Interface - // 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)) - { - udelay(10); - - ec_command_read(&cmd, node_address, 0x502, 10); - - if (unlikely(ec_simple_send_receive(master, &cmd) != 0)) - return -1; - - if (unlikely(cmd.working_counter != 1)) { - printk(KERN_ERR "EtherCAT: SII-read status -" - " Slave %04X did not respond!\n", node_address); - return -1; - } - - if (likely((cmd.data[1] & 0x81) == 0)) { - memcpy(target, cmd.data + 6, 4); - break; - } - - tries_left--; - } - - if (unlikely(!tries_left)) { - printk(KERN_WARNING "EtherCAT: SSI-read. Slave %04X timed out!\n", - node_address); - return -1; - } - - return 0; -} - -/*****************************************************************************/ - -/** - Ändert den Zustand eines Slaves. - - \return 0 bei Erfolg, sonst < 0 -*/ - -int ec_state_change(ec_master_t *master, - /**station_address, 0x0120, 2, data); - - if (unlikely(ec_simple_send_receive(master, &cmd) != 0)) { - printk(KERN_ERR "EtherCAT: Could not set state %02X - Unable to send!\n", - state_and_ack); - return -1; - } - - if (unlikely(cmd.working_counter != 1)) { - printk(KERN_ERR "EtherCAT: Could not set state %02X - Slave %i did not" - " respond!\n", state_and_ack, slave->ring_position * (-1)); - return -1; - } - - tries_left = 100; - while (likely(tries_left)) - { - udelay(10); - - ec_command_read(&cmd, slave->station_address, 0x0130, 2); - - if (unlikely(ec_simple_send_receive(master, &cmd) != 0)) { - printk(KERN_ERR "EtherCAT: Could not check state %02X - Unable to" - " send!\n", state_and_ack); - return -1; - } - - if (unlikely(cmd.working_counter != 1)) { - printk(KERN_ERR "EtherCAT: Could not check state %02X - Device %i did" - " not respond!\n", state_and_ack, slave->ring_position * (-1)); - return -1; - } - - if (unlikely(cmd.data[0] & 0x10)) { // State change error - printk(KERN_ERR "EtherCAT: Could not set state %02X - Device %i refused" - " state change (code %02X)!\n", state_and_ack, - slave->ring_position * (-1), cmd.data[0]); - return -1; - } - - if (likely(cmd.data[0] == (state_and_ack & 0x0F))) { - // State change successful - break; - } - - tries_left--; - } - - if (unlikely(!tries_left)) { - printk(KERN_ERR "EtherCAT: Could not check state %02X of slave %i -" - " Timeout while checking!\n", state_and_ack, - slave->ring_position * (-1)); - return -1; - } - - return 0; -} - -/*****************************************************************************/ - -/** - Gibt Frame-Inhalte zwecks Debugging aus. -*/ - -void ec_output_debug_data(const ec_master_t *master /**< EtherCAT-Master */) -{ - unsigned int i; - - printk(KERN_DEBUG "EtherCAT: tx_data content (%i Bytes):\n", - master->tx_data_length); - - printk(KERN_DEBUG); - for (i = 0; i < master->tx_data_length; i++) - { - printk("%02X ", master->tx_data[i]); - if ((i + 1) % 16 == 0) printk("\n" KERN_DEBUG); - } - printk("\n"); - - printk(KERN_DEBUG "EtherCAT: rx_data content (%i Bytes):\n", - master->rx_data_length); - - printk(KERN_DEBUG); - for (i = 0; i < master->rx_data_length; i++) - { - printk("%02X ", master->rx_data[i]); - if ((i + 1) % 16 == 0) printk("\n" KERN_DEBUG); - } - printk("\n"); + slave = master->slaves + i; + + // Write station address + data[0] = slave->station_address & 0x00FF; + data[1] = (slave->station_address & 0xFF00) >> 8; + + ec_frame_init_apwr(&frame, master, slave->ring_position, 0x0010, 2, + data); + + if (unlikely(ec_frame_send_receive(&frame) < 0)) return -1; + + if (unlikely(frame.working_counter != 1)) { + printk(KERN_ERR "EtherCAT: Slave %i did not repond while writing" + " station address!\n", i); + return -1; + } + + // Fetch all slave information + if (ec_slave_fetch(slave)) return -1; + + // Search for identification in "database" + ident = slave_idents; + while (ident) { + if (unlikely(ident->vendor_id == slave->sii_vendor_id + && ident->product_code == slave->sii_product_code)) { + slave->type = ident->type; + break; + } + ident++; + } + + if (!slave->type) { + printk(KERN_WARNING "EtherCAT: Unknown slave device (vendor" + " 0x%08X, code 0x%08X) at position %i.\n", + slave->sii_vendor_id, slave->sii_product_code, i); + return 0; + } + } + + return 0; } /*****************************************************************************/ @@ -700,16 +236,17 @@ void ec_output_lost_frames(ec_master_t *master /**< EtherCAT-Master */) { - unsigned long int t; - - if (master->frames_lost) { - rdtscl(t); - if ((t - master->t_lost_output) / cpu_khz > 1000) { - printk(KERN_ERR "EtherCAT: %u frame(s) LOST!\n", master->frames_lost); - master->frames_lost = 0; - master->t_lost_output = t; - } - } + unsigned long int t; + + if (master->frames_lost) { + rdtscl(t); + if ((t - master->t_lost_output) / cpu_khz > 1000) { + printk(KERN_ERR "EtherCAT: %u frame(s) LOST!\n", + master->frames_lost); + master->frames_lost = 0; + master->t_lost_output = t; + } + } } /*****************************************************************************/ @@ -733,69 +270,129 @@ /**< Address-String */ ) { - unsigned long first, second; - char *remainder, *remainder2; - unsigned int i; - int coupler_idx, slave_idx; - ec_slave_t *slave; - - if (!address || address[0] == 0) return NULL; - - if (address[0] == '#') { - printk(KERN_ERR "EtherCAT: Bus ID - # not implemented yet!\n"); + unsigned long first, second; + char *remainder, *remainder2; + unsigned int i; + int coupler_idx, slave_idx; + ec_slave_t *slave; + + if (!address || address[0] == 0) return NULL; + + if (address[0] == '#') { + printk(KERN_ERR "EtherCAT: Bus ID \"%s\" - # not implemented" + " yet!\n", address); + return NULL; + } + + first = simple_strtoul(address, &remainder, 0); + if (remainder == address) { + printk(KERN_ERR "EtherCAT: Bus ID \"%s\" - First number empty!\n", + address); + return NULL; + } + + if (!remainder[0]) { // absolute position + if (first < master->slave_count) { + return master->slaves + first; + } + + printk(KERN_ERR "EtherCAT: Bus ID \"%s\" - Absolute position" + " illegal!\n", address); + } + + else if (remainder[0] == ':') { // field position + + remainder++; + second = simple_strtoul(remainder, &remainder2, 0); + + if (remainder2 == remainder) { + printk(KERN_ERR "EtherCAT: Bus ID \"%s\" - Sencond number" + " empty!\n", address); + return NULL; + } + + if (remainder2[0]) { + printk(KERN_ERR "EtherCAT: Bus ID \"%s\" - Illegal trailer" + " (2)!\n", address); + return NULL; + } + + coupler_idx = -1; + slave_idx = 0; + for (i = 0; i < master->slave_count; i++, slave_idx++) { + slave = master->slaves + i; + if (!slave->type) continue; + + if (strcmp(slave->type->vendor_name, "Beckhoff") == 0 && + strcmp(slave->type->product_name, "EK1100") == 0) { + coupler_idx++; + slave_idx = 0; + } + + if (coupler_idx == first && slave_idx == second) return slave; + } + } + + else { + printk(KERN_ERR "EtherCAT: Bus ID \"%s\" - Illegal trailer!\n", + address); + } + return NULL; - } - - first = simple_strtoul(address, &remainder, 0); - if (remainder == address) { - printk(KERN_ERR "EtherCAT: Bus ID - First number empty!\n"); - return NULL; - } - - if (!remainder[0]) { // absolute position - if (first < master->bus_slaves_count) { - return master->bus_slaves + first; - } - - printk(KERN_ERR "EtherCAT: Bus ID - Absolute position illegal!\n"); - } - - else if (remainder[0] == ':') { // field position - - remainder++; - second = simple_strtoul(remainder, &remainder2, 0); - - if (remainder2 == remainder) { - printk(KERN_ERR "EtherCAT: Bus ID - Sencond number empty!\n"); - return NULL; - } - - if (remainder2[0]) { - printk(KERN_ERR "EtherCAT: Bus ID - Illegal trailer (2)!\n"); - return NULL; - } - - coupler_idx = -1; - slave_idx = 0; - for (i = 0; i < master->bus_slaves_count; i++, slave_idx++) { - slave = master->bus_slaves + i; - if (!slave->type) continue; - - if (strcmp(slave->type->vendor_name, "Beckhoff") == 0 && - strcmp(slave->type->product_name, "EK1100") == 0) { - coupler_idx++; - slave_idx = 0; - } - - if (coupler_idx == first && slave_idx == second) return slave; - } - } - - else { - printk(KERN_ERR "EtherCAT: Bus ID - Illegal trailer!\n"); - } - - return NULL; +} + +/*****************************************************************************/ + +/** + Initialisiert eine Sync-Manager-Konfigurationsseite. + + Der mit \a data referenzierte Speicher muss mindestens EC_SYNC_SIZE Bytes + groß sein. +*/ + +void ec_sync_config(const ec_sync_t *sync, /**< Sync-Manager */ + uint8_t *data /**> Zeiger auf Konfigurationsspeicher */ + ) +{ + data[0] = sync->physical_start_address & 0xFF; + data[1] = (sync->physical_start_address >> 8) & 0xFF; + data[2] = sync->size & 0xFF; + data[3] = (sync->size >> 8) & 0xFF; + data[4] = sync->control_byte; + data[5] = 0x00; + data[6] = 0x01; // enable + data[7] = 0x00; +} + +/*****************************************************************************/ + +/** + Initialisiert eine FMMU-Konfigurationsseite. + + Der mit \a data referenzierte Speicher muss mindestens EC_FMMU_SIZE Bytes + groß sein. +*/ + +void ec_fmmu_config(const ec_fmmu_t *fmmu, /**< Sync-Manager */ + uint8_t *data /**> Zeiger auf Konfigurationsspeicher */ + ) +{ + data[0] = fmmu->logical_start_address & 0xFF; + data[1] = (fmmu->logical_start_address >> 8) & 0xFF; + data[2] = (fmmu->logical_start_address >> 16) & 0xFF; + data[3] = (fmmu->logical_start_address >> 24) & 0xFF; + data[4] = fmmu->sync->size & 0xFF; + data[5] = (fmmu->sync->size >> 8) & 0xFF; + data[6] = 0x00; // Logical start bit + data[7] = 0x07; // Logical end bit + data[8] = fmmu->sync->physical_start_address & 0xFF; + data[9] = (fmmu->sync->physical_start_address >> 8) & 0xFF; + data[10] = 0x00; // Physical start bit + data[11] = (fmmu->sync->control_byte & 0x04) ? 0x02 : 0x01; + data[12] = 0x01; // Enable + data[13] = 0x00; // res. + data[14] = 0x00; // res. + data[15] = 0x00; // res. } /****************************************************************************** @@ -805,133 +402,37 @@ *****************************************************************************/ /** - Registriert einen Slave beim Master. - - \return Zeiger auf den Slave bei Erfolg, sonst NULL -*/ - -ec_slave_t *EtherCAT_rt_register_slave(ec_master_t *master, - /**< EtherCAT-Master */ - const char *address, - /**< ASCII-Addresse des Slaves, siehe - auch ec_address() */ - const char *vendor_name, - /**< Herstellername */ - const char *product_name, - /**< Produktname */ - int domain - /**< Domäne */ - ) -{ - ec_slave_t *slave; - const ec_slave_type_t *type; - ec_domain_t *dom; - unsigned int j; - - if (domain < 0) { - printk(KERN_ERR "EtherCAT: Invalid domain: %i\n", domain); - return NULL; - } - - if ((slave = ec_address(master, address)) == NULL) { - printk(KERN_ERR "EtherCAT: Illegal address: \"%s\"\n", address); - return NULL; - } - - if (slave->registered) { - printk(KERN_ERR "EtherCAT: Slave \"%s\" (position %i) has already been" - " registered!\n", address, slave->ring_position * (-1)); - return NULL; - } - - if (!slave->type) { - printk(KERN_ERR "EtherCAT: Slave \"%s\" (position %i) has unknown type!\n", - address, slave->ring_position * (-1)); - return NULL; - } - - type = slave->type; - - if (strcmp(vendor_name, type->vendor_name) || - strcmp(product_name, type->product_name)) { - printk(KERN_ERR "Invalid Slave Type! Requested: \"%s %s\", found: \"%s" - " %s\".\n", vendor_name, product_name, type->vendor_name, - type->product_name); - return NULL; - } - - // Check, if process data domain already exists... - dom = NULL; - for (j = 0; j < master->domain_count; j++) { - if (domain == master->domains[j].number) { - dom = master->domains + j; - break; - } - } - - // Create process data domain - if (!dom) { - if (master->domain_count > EC_MAX_DOMAINS - 1) { - printk(KERN_ERR "EtherCAT: Too many domains!\n"); - return NULL; - } - - dom = master->domains + master->domain_count; - ec_domain_init(dom); - dom->number = domain; - dom->logical_offset = master->domain_count * EC_FRAME_SIZE; + Registriert eine neue Domäne. + + \return Zeiger auf die Domäne bei Erfolg, sonst NULL. +*/ + +ec_domain_t *EtherCAT_rt_master_register_domain(ec_master_t *master, + /**< Domäne */ + ec_domain_mode_t mode, + /**< Modus */ + unsigned int timeout_us + /**< Timeout */ + ) +{ + ec_domain_t *domain; + + if (master->domain_count >= EC_MASTER_MAX_DOMAINS) { + printk(KERN_ERR "EtherCAT: Maximum number of domains reached!\n"); + return NULL; + } + + if (!(domain = (ec_domain_t *) kmalloc(sizeof(ec_domain_t), GFP_KERNEL))) { + printk(KERN_ERR "EthertCAT: Error allocating domain memory!\n"); + return NULL; + } + + ec_domain_init(domain, master, mode, timeout_us); + master->domains[master->domain_count] = domain; master->domain_count++; - } - - if (dom->data_size + type->process_data_size > EC_FRAME_SIZE - 14) { - printk(KERN_ERR "EtherCAT: Oversized domain %i: %i / %i Bytes!\n", - dom->number, dom->data_size + type->process_data_size, - EC_FRAME_SIZE - 14); - return NULL; - } - - slave->process_data = dom->data + dom->data_size; - slave->logical_address = dom->data_size; - slave->registered = 1; - - dom->data_size += type->process_data_size; - - return slave; -} - -/*****************************************************************************/ - -/** - Registriert eine ganze Liste von Slaves beim Master. - - \return 0 bei Erfolg, sonst < 0 -*/ - -int EtherCAT_rt_register_slave_list(ec_master_t *master, - /**< EtherCAT-Master */ - const ec_slave_init_t *slaves, - /**< Array von Slave-Initialisierungs- - strukturen */ - unsigned int count - /**< Anzahl der Strukturen in \a slaves */ - ) -{ - unsigned int i; - - for (i = 0; i < count; i++) - { - if ((*(slaves[i].slave_ptr) = - EtherCAT_rt_register_slave(master, slaves[i].address, - slaves[i].vendor_name, - slaves[i].product_name, - slaves[i].domain)) == NULL) - return -1; - } - - return 0; -} - -/*****************************************************************************/ + + return domain; +} /** Konfiguriert alle Slaves und setzt den Operational-Zustand. @@ -943,313 +444,148 @@ \return 0 bei Erfolg, sonst < 0 */ -int EtherCAT_rt_activate_slaves(ec_master_t *master /**< EtherCAT-Master */) -{ - unsigned int i; - ec_slave_t *slave; - ec_command_t cmd; - const ec_slave_type_t *type; - unsigned char fmmu[16]; - unsigned char data[256]; - - for (i = 0; i < master->bus_slaves_count; i++) - { - slave = master->bus_slaves + i; - - if (unlikely(ec_state_change(master, slave, EC_SLAVE_STATE_INIT) != 0)) - return -1; - - // Check if slave was registered... - if (!slave->registered) { - printk(KERN_INFO "EtherCAT: Slave %i was not registered.\n", i); - continue; - } - - type = slave->type; - - // Resetting FMMU's - - memset(data, 0x00, 256); - - ec_command_write(&cmd, slave->station_address, 0x0600, 256, data); - - if (unlikely(ec_simple_send_receive(master, &cmd) < 0)) - return -1; - - if (unlikely(cmd.working_counter != 1)) { - printk(KERN_ERR "EtherCAT: Resetting FMMUs - Slave %04X did not" - " respond!\n", slave->station_address); - return -1; - } - - // Resetting Sync Manager channels - - if (type->features != EC_NOSYNC_SLAVE) +int EtherCAT_rt_master_activate(ec_master_t *master /**< EtherCAT-Master */) +{ + unsigned int i, j; + ec_slave_t *slave; + ec_frame_t frame; + const ec_sync_t *sync; + const ec_slave_type_t *type; + const ec_fmmu_t *fmmu; + uint8_t data[256]; + uint32_t domain_offset; + + // Domains erstellen + domain_offset = 0; + for (i = 0; i < master->domain_count; i++) { + ec_domain_t *domain = master->domains[i]; + if (ec_domain_alloc(domain, domain_offset)) { + printk(KERN_INFO "EtherCAT: Failed to allocate domain %i!\n", i); + return -1; + } + printk(KERN_INFO "EtherCAT: Domain %i - Allocated %i bytes (%i" + " Frame(s))\n", i, domain->data_size, + domain->data_size / EC_MAX_FRAME_SIZE + 1); + domain_offset += domain->data_size; + } + + // Slaves aktivieren + for (i = 0; i < master->slave_count; i++) { - memset(data, 0x00, 256); - - ec_command_write(&cmd, slave->station_address, 0x0800, 256, data); - - if (unlikely(ec_simple_send_receive(master, &cmd) < 0)) - return -1; - - if (unlikely(cmd.working_counter != 1)) { - printk(KERN_ERR "EtherCAT: Resetting SMs - Slave %04X did not" - " respond!\n", slave->station_address); - return -1; - } - } - - // Init Mailbox communication - - if (type->features == EC_MAILBOX_SLAVE) + slave = master->slaves + i; + + // Change state to INIT + if (unlikely(ec_slave_state_change(slave, EC_SLAVE_STATE_INIT))) + return -1; + + // Check if slave was registered... + if (!slave->type || !slave->registered) { + printk(KERN_INFO "EtherCAT: Slave %i was not registered.\n", i); + continue; + } + + type = slave->type; + + // Resetting FMMU's + 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) < 0)) return -1; + if (unlikely(frame.working_counter != 1)) { + printk(KERN_ERR "EtherCAT: Resetting FMMUs - Slave %i did" + " not respond!\n", slave->ring_position); + return -1; + } + } + + // 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) < 0)) return -1; + if (unlikely(frame.working_counter != 1)) { + printk(KERN_ERR "EtherCAT: Resetting SMs - Slave %i did not" + " respond!\n", slave->ring_position); + return -1; + } + } + + // Set Sync Managers + for (j = 0; type->sync_managers[j] && j < EC_MAX_SYNC; j++) + { + 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))) return -1; + + if (unlikely(frame.working_counter != 1)) { + printk(KERN_ERR "EtherCAT: Setting sync manager %i - Slave" + " %i did not respond!\n", j, slave->ring_position); + return -1; + } + } + + // Change state to PREOP + if (unlikely(ec_slave_state_change(slave, EC_SLAVE_STATE_PREOP))) + return -1; + + // Set FMMUs + for (j = 0; j < slave->fmmu_count; j++) + { + 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))) return -1; + + if (unlikely(frame.working_counter != 1)) { + printk(KERN_ERR "EtherCAT: Setting FMMU %i - Slave %i did not" + " respond!\n", j, slave->ring_position); + return -1; + } + } + + // Change state to SAVEOP + if (unlikely(ec_slave_state_change(slave, EC_SLAVE_STATE_SAVEOP))) + return -1; + + // Change state to OP + if (unlikely(ec_slave_state_change(slave, EC_SLAVE_STATE_OP))) + return -1; + } + + return 0; +} + +/*****************************************************************************/ + +/** + Setzt alle Slaves zurück in den Init-Zustand. + + \return 0 bei Erfolg, sonst < 0 +*/ + +int EtherCAT_rt_master_deactivate(ec_master_t *master /**< EtherCAT-Master */) +{ + ec_slave_t *slave; + unsigned int i; + + for (i = 0; i < master->slave_count; i++) { - if (type->sm0) - { - ec_command_write(&cmd, slave->station_address, 0x0800, 8, type->sm0); - - if (unlikely(ec_simple_send_receive(master, &cmd) < 0)) - return -1; - - if (unlikely(cmd.working_counter != 1)) { - printk(KERN_ERR "EtherCAT: Setting SM0 - Slave %04X did not" - " respond!\n", slave->station_address); - return -1; - } - } - - if (type->sm1) - { - ec_command_write(&cmd, slave->station_address, 0x0808, 8, type->sm1); - - if (unlikely(ec_simple_send_receive(master, &cmd) < 0)) - return -1; - - if (unlikely(cmd.working_counter != 1)) { - printk(KERN_ERR "EtherCAT: Setting SM1 -" - " Slave %04X did not respond!\n", - slave->station_address); - return -1; - } - } - } - - // Change state to PREOP - - if (unlikely(ec_state_change(master, slave, EC_SLAVE_STATE_PREOP) != 0)) - return -1; - - // Set FMMU's - - if (type->fmmu0) - { - if (unlikely(!slave->process_data)) { - printk(KERN_ERR "EtherCAT: Warning - Slave %04X is not assigned to any" - " process data object!\n", slave->station_address); - return -1; - } - - memcpy(fmmu, type->fmmu0, 16); - - fmmu[0] = slave->logical_address & 0x000000FF; - fmmu[1] = (slave->logical_address & 0x0000FF00) >> 8; - fmmu[2] = (slave->logical_address & 0x00FF0000) >> 16; - fmmu[3] = (slave->logical_address & 0xFF000000) >> 24; - - ec_command_write(&cmd, slave->station_address, 0x0600, 16, fmmu); - - if (unlikely(ec_simple_send_receive(master, &cmd) < 0)) - return -1; - - if (unlikely(cmd.working_counter != 1)) { - printk(KERN_ERR "EtherCAT: Setting FMMU0 - Slave %04X did not" - " respond!\n", slave->station_address); - return -1; - } - } - - // Set Sync Managers - - if (type->features != EC_MAILBOX_SLAVE) - { - if (type->sm0) - { - ec_command_write(&cmd, slave->station_address, 0x0800, 8, type->sm0); - - if (unlikely(ec_simple_send_receive(master, &cmd) < 0)) - return -1; - - if (unlikely(cmd.working_counter != 1)) { - printk(KERN_ERR "EtherCAT: Setting SM0 - Slave %04X did not" - " respond!\n", slave->station_address); - return -1; - } - } - - if (type->sm1) - { - ec_command_write(&cmd, slave->station_address, 0x0808, 8, type->sm1); - - if (unlikely(ec_simple_send_receive(master, &cmd) < 0)) - return -1; - - if (unlikely(cmd.working_counter != 1)) { - printk(KERN_ERR "EtherCAT: Setting SM1 - Slave %04X did not" - " respond!\n", slave->station_address); - return -1; - } - } - } - - if (type->sm2) - { - ec_command_write(&cmd, slave->station_address, 0x0810, 8, type->sm2); - - if (unlikely(ec_simple_send_receive(master, &cmd) < 0)) - return -1; - - if (unlikely(cmd.working_counter != 1)) { - printk(KERN_ERR "EtherCAT: Setting SM2 - Slave %04X did not" - " respond!\n", slave->station_address); - return -1; - } - } - - if (type->sm3) - { - ec_command_write(&cmd, slave->station_address, 0x0818, 8, type->sm3); - - if (unlikely(ec_simple_send_receive(master, &cmd) < 0)) - return -1; - - if (unlikely(cmd.working_counter != 1)) { - printk(KERN_ERR "EtherCAT: Setting SM3 - Slave %04X did not" - " respond!\n", slave->station_address); - return -1; - } - } - - // Change state to SAVEOP - if (unlikely(ec_state_change(master, slave, EC_SLAVE_STATE_SAVEOP) != 0)) - return -1; - - // Change state to OP - if (unlikely(ec_state_change(master, slave, EC_SLAVE_STATE_OP) != 0)) - return -1; - } - - return 0; -} - -/*****************************************************************************/ - -/** - Setzt alle Slaves zurück in den Init-Zustand. - - \return 0 bei Erfolg, sonst < 0 -*/ - -int EtherCAT_rt_deactivate_slaves(ec_master_t *master /**< EtherCAT-Master */) -{ - ec_slave_t *slave; - unsigned int i; - - for (i = 0; i < master->bus_slaves_count; i++) - { - slave = master->bus_slaves + i; - - if (unlikely(ec_state_change(master, slave, EC_SLAVE_STATE_INIT) != 0)) - return -1; - } - - return 0; -} - -/*****************************************************************************/ - -/** - Sendet und empfängt Prozessdaten der angegebenen Domäne - - \return 0 bei Erfolg, sonst < 0 -*/ - -int EtherCAT_rt_domain_xio(ec_master_t *master, - /**< EtherCAT-Master */ - unsigned int domain, - /**< Domäne */ - unsigned int timeout_us - /**< Timeout in Mikrosekunden */ - ) -{ - unsigned int i; - ec_domain_t *dom; - unsigned long start_ticks, end_ticks, timeout_ticks; - - ec_output_lost_frames(master); // Evtl. verlorene Frames ausgeben - - // Domäne bestimmen - dom = NULL; - for (i = 0; i < master->domain_count; i++) { - if (master->domains[i].number == domain) { - dom = master->domains + i; - break; - } - } - - if (unlikely(!dom)) { - printk(KERN_ERR "EtherCAT: No such domain: %i!\n", domain); - return -1; - } - - ec_command_logical_read_write(&dom->command, dom->logical_offset, - dom->data_size, dom->data); - - rdtscl(start_ticks); // Sendezeit nehmen - - if (unlikely(ec_simple_send(master, &dom->command) < 0)) { - printk(KERN_ERR "EtherCAT: Could not send process data command!\n"); - return -1; - } - - timeout_ticks = timeout_us * cpu_khz / 1000; - - // 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)) { - master->device.state = EC_DEVICE_STATE_READY; - master->frames_lost++; - ec_output_lost_frames(master); - return -1; - } - - if (unlikely(ec_simple_receive(master, &dom->command) < 0)) { - printk(KERN_ERR "EtherCAT: Could not receive cyclic command!\n"); - return -1; - } - - if (unlikely(dom->command.state != EC_COMMAND_STATE_RECEIVED)) { - printk(KERN_WARNING "EtherCAT: Process data command not received!\n"); - return -1; - } - - if (dom->command.working_counter != dom->response_count) { - dom->response_count = dom->command.working_counter; - printk(KERN_INFO "EtherCAT: Domain %i State change - %i slaves" - " responding.\n", dom->number, dom->response_count); - } - - // Daten vom Kommando in den Prozessdatenspeicher kopieren - memcpy(dom->data, dom->command.data, dom->data_size); - - return 0; + slave = master->slaves + i; + + if (unlikely(ec_slave_state_change(slave, EC_SLAVE_STATE_INIT) != 0)) + return -1; + } + + return 0; } /*****************************************************************************/ @@ -1263,28 +599,50 @@ - 2: Komplette Frame-Inhalte */ -void EtherCAT_rt_debug_level(ec_master_t *master, - /**< EtherCAT-Master */ - int level - /**< Debug-Level */ - ) -{ - master->debug_level = level; -} - -/*****************************************************************************/ - -EXPORT_SYMBOL(EtherCAT_rt_register_slave); -EXPORT_SYMBOL(EtherCAT_rt_register_slave_list); -EXPORT_SYMBOL(EtherCAT_rt_activate_slaves); -EXPORT_SYMBOL(EtherCAT_rt_deactivate_slaves); -EXPORT_SYMBOL(EtherCAT_rt_domain_xio); -EXPORT_SYMBOL(EtherCAT_rt_debug_level); +void EtherCAT_rt_master_debug(ec_master_t *master, + /**< EtherCAT-Master */ + int level + /**< Debug-Level */ + ) +{ + master->debug_level = level; + + printk(KERN_INFO "EtherCAT: Master debug level set to %i.\n", level); +} + +/*****************************************************************************/ + +/** + Gibt alle Informationen zum Master aus. +*/ + +void EtherCAT_rt_master_print(const ec_master_t *master + /**< EtherCAT-Master */ + ) +{ + unsigned int i; + + printk(KERN_INFO "EtherCAT: *** Begin master information ***\n"); + + for (i = 0; i < master->slave_count; i++) { + ec_slave_print(&master->slaves[i]); + } + + printk(KERN_INFO "EtherCAT: *** End master information ***\n"); +} + +/*****************************************************************************/ + +EXPORT_SYMBOL(EtherCAT_rt_master_register_domain); +EXPORT_SYMBOL(EtherCAT_rt_master_activate); +EXPORT_SYMBOL(EtherCAT_rt_master_deactivate); +EXPORT_SYMBOL(EtherCAT_rt_master_debug); +EXPORT_SYMBOL(EtherCAT_rt_master_print); /*****************************************************************************/ /* Emacs-Konfiguration ;;; Local Variables: *** -;;; c-basic-offset:2 *** +;;; c-basic-offset:4 *** ;;; End: *** */ diff -r 7c986b717411 -r 9f4ea66d89a3 master/master.h --- a/master/master.h Wed Feb 22 17:36:28 2006 +0000 +++ b/master/master.h Thu Feb 23 09:58:50 2006 +0000 @@ -13,7 +13,7 @@ #include "device.h" #include "slave.h" -#include "command.h" +#include "frame.h" #include "domain.h" /*****************************************************************************/ @@ -27,25 +27,18 @@ struct ec_master { - ec_slave_t *bus_slaves; /**< Array von Slaves auf dem Bus */ - unsigned int bus_slaves_count; /**< Anzahl Slaves auf dem Bus */ - ec_device_t device; /**< EtherCAT-Gerät */ - unsigned int device_registered; /**< Ein Geraet hat sich registriert. */ - unsigned char command_index; /**< Aktueller Kommando-Index */ - unsigned char tx_data[EC_FRAME_SIZE]; /**< Statischer Speicher - für zu sendende Daten */ - unsigned int tx_data_length; /**< Länge der Daten im Sendespeicher */ - unsigned char rx_data[EC_FRAME_SIZE]; /**< Statische Speicher für - eine Kopie des Rx-Buffers - im EtherCAT-Gerät */ - unsigned int rx_data_length; /**< Länge der Daten im Empfangsspeicher */ - ec_domain_t domains[EC_MAX_DOMAINS]; /** Prozessdatendomänen */ - unsigned int domain_count; - int debug_level; /**< Debug-Level im Master-Code */ - unsigned int bus_time; /**< Letzte Bus-Zeit in Mikrosekunden */ - unsigned int frames_lost; /**< Anzahl verlorene Frames */ - unsigned long t_lost_output; /*<< Timer-Ticks bei der letzten Ausgabe von - verlorenen Frames */ + 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. */ + uint8_t command_index; /**< Aktueller Kommando-Index */ + ec_domain_t *domains[EC_MASTER_MAX_DOMAINS]; /** Prozessdatendomänen */ + unsigned int domain_count; + int debug_level; /**< Debug-Level im Master-Code */ + unsigned int bus_time; /**< Letzte Bus-Zeit in Mikrosekunden */ + unsigned int frames_lost; /**< Anzahl verlorene Frames */ + unsigned long t_lost_output; /*<< Timer-Ticks bei der letzten Ausgabe von + verlorenen Frames */ }; /*****************************************************************************/ @@ -63,8 +56,9 @@ int ec_scan_for_slaves(ec_master_t *); ec_slave_t *ec_address(const ec_master_t *, const char *); -// Data -int ec_simple_send_receive(ec_master_t *, ec_command_t *); +// Misc +void ec_output_debug_data(const ec_master_t *); +void ec_output_lost_frames(ec_master_t *); /*****************************************************************************/ @@ -72,6 +66,6 @@ /* Emacs-Konfiguration ;;; Local Variables: *** -;;; c-basic-offset:2 *** +;;; c-basic-offset:4 *** ;;; End: *** */ diff -r 7c986b717411 -r 9f4ea66d89a3 master/module.c --- a/master/module.c Wed Feb 22 17:36:28 2006 +0000 +++ b/master/module.c Thu Feb 23 09:58:50 2006 +0000 @@ -69,46 +69,45 @@ int __init ec_init_module(void) { - unsigned int i; - - printk(KERN_ERR "EtherCAT: Master driver, %s\n", COMPILE_INFO); - - if (ec_master_count < 1) { - printk(KERN_ERR "EtherCAT: Error - Illegal" - " ec_master_count: %i\n", ec_master_count); - return -1; - } - - printk(KERN_ERR "EtherCAT: Initializing %i EtherCAT master(s)...\n", - ec_master_count); - - if ((ec_masters = - (ec_master_t *) kmalloc(sizeof(ec_master_t) - * ec_master_count, - GFP_KERNEL)) == NULL) { - printk(KERN_ERR "EtherCAT: Could not allocate" - " memory for EtherCAT master(s)!\n"); - return -1; - } - - if ((ec_masters_reserved = - (int *) kmalloc(sizeof(int) * ec_master_count, - GFP_KERNEL)) == NULL) { - printk(KERN_ERR "EtherCAT: Could not allocate" - " memory for reservation flags!\n"); - kfree(ec_masters); - return -1; - } - - for (i = 0; i < ec_master_count; i++) - { - ec_master_init(&ec_masters[i]); - ec_masters_reserved[i] = 0; - } - - printk(KERN_ERR "EtherCAT: Master driver initialized.\n"); - - return 0; + unsigned int i; + + printk(KERN_ERR "EtherCAT: Master driver, %s\n", COMPILE_INFO); + + if (ec_master_count < 1) { + printk(KERN_ERR "EtherCAT: Error - Illegal" + " ec_master_count: %i\n", ec_master_count); + return -1; + } + + printk(KERN_ERR "EtherCAT: Initializing %i EtherCAT master(s)...\n", + ec_master_count); + + if ((ec_masters = + (ec_master_t *) kmalloc(sizeof(ec_master_t) + * ec_master_count, + GFP_KERNEL)) == NULL) { + printk(KERN_ERR "EtherCAT: Could not allocate" + " memory for EtherCAT master(s)!\n"); + return -1; + } + + if ((ec_masters_reserved = + (int *) kmalloc(sizeof(int) * ec_master_count, + GFP_KERNEL)) == NULL) { + printk(KERN_ERR "EtherCAT: Could not allocate" + " memory for reservation flags!\n"); + kfree(ec_masters); + return -1; + } + + for (i = 0; i < ec_master_count; i++) { + ec_master_init(ec_masters + i); + ec_masters_reserved[i] = 0; + } + + printk(KERN_ERR "EtherCAT: Master driver initialized.\n"); + + return 0; } /*****************************************************************************/ @@ -121,26 +120,22 @@ void __exit ec_cleanup_module(void) { - unsigned int i; - - printk(KERN_ERR "EtherCAT: Cleaning up master driver...\n"); - - if (ec_masters) - { - for (i = 0; i < ec_master_count; i++) - { - if (ec_masters_reserved[i]) { - printk(KERN_WARNING "EtherCAT: Warning -" - " Master %i is still in use!\n", i); - } - - ec_master_clear(&ec_masters[i]); - } - - kfree(ec_masters); - } - - printk(KERN_ERR "EtherCAT: Master driver cleaned up.\n"); + unsigned int i; + + printk(KERN_ERR "EtherCAT: Cleaning up master driver...\n"); + + if (ec_masters) { + for (i = 0; i < ec_master_count; i++) { + if (ec_masters_reserved[i]) { + printk(KERN_WARNING "EtherCAT: Warning -" + " Master %i is still in use!\n", i); + } + ec_master_clear(&ec_masters[i]); + } + kfree(ec_masters); + } + + printk(KERN_ERR "EtherCAT: Master driver cleaned up.\n"); } /****************************************************************************** @@ -158,8 +153,8 @@ @param module Zeiger auf das Modul (fuer try_module_lock()) @return 0, wenn alles o.k., - < 0, wenn bereits ein Geraet registriert oder das Geraet nicht - geoeffnet werden konnte. + < 0, wenn bereits ein Geraet registriert oder das Geraet nicht + geoeffnet werden konnte. */ ec_device_t *EtherCAT_dev_register(unsigned int master_index, @@ -168,42 +163,39 @@ struct pt_regs *), struct module *module) { - ec_device_t *ecd; - ec_master_t *master; - - if (master_index >= ec_master_count) { - printk(KERN_ERR "EtherCAT: Master %i does not exist!\n", master_index); - return NULL; - } - - if (!dev) { - printk("EtherCAT: Device is NULL!\n"); - return NULL; - } - - master = ec_masters + master_index; - - if (master->device_registered) { - printk(KERN_ERR "EtherCAT: Master %i already has a device!\n", - master_index); - return NULL; - } - - ecd = &master->device; - - if (ec_device_init(ecd) < 0) { - return NULL; - } - - ecd->dev = dev; - ecd->tx_skb->dev = dev; - ecd->rx_skb->dev = dev; - ecd->isr = isr; - ecd->module = module; - - master->device_registered = 1; - - return ecd; + ec_device_t *ecd; + ec_master_t *master; + + if (master_index >= ec_master_count) { + printk(KERN_ERR "EtherCAT: Master %i does not exist!\n", master_index); + return NULL; + } + + if (!dev) { + printk("EtherCAT: Device is NULL!\n"); + return NULL; + } + + master = ec_masters + master_index; + + if (master->device_registered) { + printk(KERN_ERR "EtherCAT: Master %i already has a device!\n", + master_index); + return NULL; + } + + ecd = &master->device; + + if (ec_device_init(ecd) < 0) return NULL; + + ecd->dev = dev; + ecd->tx_skb->dev = dev; + ecd->isr = isr; + ecd->module = module; + + master->device_registered = 1; + + return ecd; } /*****************************************************************************/ @@ -217,22 +209,23 @@ void EtherCAT_dev_unregister(unsigned int master_index, ec_device_t *ecd) { - ec_master_t *master; - - if (master_index >= ec_master_count) { - printk(KERN_WARNING "EtherCAT: Master %i does not exist!\n", master_index); - return; - } - - master = ec_masters + master_index; - - if (!master->device_registered || &master->device != ecd) { - printk(KERN_ERR "EtherCAT: Unable to unregister device!\n"); - return; - } - - master->device_registered = 0; - ec_device_clear(ecd); + ec_master_t *master; + + if (master_index >= ec_master_count) { + printk(KERN_WARNING "EtherCAT: Master %i does not exist!\n", + master_index); + return; + } + + master = ec_masters + master_index; + + if (!master->device_registered || &master->device != ecd) { + printk(KERN_ERR "EtherCAT: Unable to unregister device!\n"); + return; + } + + master->device_registered = 0; + ec_device_clear(ecd); } /****************************************************************************** @@ -252,54 +245,54 @@ ec_master_t *EtherCAT_rt_request_master(unsigned int index) { - ec_master_t *master; - - if (index < 0 || index >= ec_master_count) { - printk(KERN_ERR "EtherCAT: Master %i does not exist!\n", index); - goto req_return; - } - - if (ec_masters_reserved[index]) { - printk(KERN_ERR "EtherCAT: Master %i already in use!\n", index); - goto req_return; - } - - master = &ec_masters[index]; - - if (!master->device_registered) { - printk(KERN_ERR "EtherCAT: Master %i has no device assigned yet!\n", - index); - goto req_return; - } - - if (!try_module_get(master->device.module)) { - printk(KERN_ERR "EtherCAT: Could not reserve device module!\n"); - goto req_return; - } - - if (ec_master_open(master) < 0) { - printk(KERN_ERR "EtherCAT: Could not open device!\n"); - goto req_module_put; - } - - if (ec_scan_for_slaves(master) != 0) { - printk(KERN_ERR "EtherCAT: Could not scan for slaves!\n"); - goto req_close; - } - - ec_masters_reserved[index] = 1; - printk(KERN_INFO "EtherCAT: Reserved master %i.\n", index); - - return master; + ec_master_t *master; + + if (index < 0 || index >= ec_master_count) { + printk(KERN_ERR "EtherCAT: Master %i does not exist!\n", index); + goto req_return; + } + + if (ec_masters_reserved[index]) { + printk(KERN_ERR "EtherCAT: Master %i already in use!\n", index); + goto req_return; + } + + master = &ec_masters[index]; + + if (!master->device_registered) { + printk(KERN_ERR "EtherCAT: Master %i has no device assigned yet!\n", + index); + goto req_return; + } + + if (!try_module_get(master->device.module)) { + printk(KERN_ERR "EtherCAT: Failed to reserve device module!\n"); + goto req_return; + } + + if (ec_master_open(master) < 0) { + printk(KERN_ERR "EtherCAT: Failed to open device!\n"); + goto req_module_put; + } + + if (ec_scan_for_slaves(master) != 0) { + printk(KERN_ERR "EtherCAT: Bus scan failed!\n"); + goto req_close; + } + + ec_masters_reserved[index] = 1; + printk(KERN_INFO "EtherCAT: Reserved master %i.\n", index); + + return master; req_close: - ec_master_close(master); + ec_master_close(master); req_module_put: - module_put(master->device.module); + module_put(master->device.module); req_return: - return NULL; + return NULL; } /*****************************************************************************/ @@ -312,32 +305,32 @@ void EtherCAT_rt_release_master(ec_master_t *master) { - unsigned int i; - - for (i = 0; i < ec_master_count; i++) - { - if (&ec_masters[i] == master) + unsigned int i; + + for (i = 0; i < ec_master_count; i++) { - if (!master->device_registered) { - printk(KERN_WARNING "EtherCAT: Could not release device" - "module because of no device!\n"); - return; - } - - ec_master_close(master); - ec_master_reset(master); - - module_put(master->device.module); - ec_masters_reserved[i] = 0; - - printk(KERN_INFO "EtherCAT: Released master %i.\n", i); - - return; - } - } - - printk(KERN_WARNING "EtherCAT: Master %X was never requested!\n", - (unsigned int) master); + if (&ec_masters[i] == master) + { + if (!master->device_registered) { + printk(KERN_WARNING "EtherCAT: Failed to release device" + "module because of no device!\n"); + return; + } + + ec_master_close(master); + ec_master_reset(master); + + module_put(master->device.module); + ec_masters_reserved[i] = 0; + + printk(KERN_INFO "EtherCAT: Released master %i.\n", i); + + return; + } + } + + printk(KERN_WARNING "EtherCAT: Master %X was never requested!\n", + (unsigned int) master); } /*****************************************************************************/ @@ -354,6 +347,6 @@ /* Emacs-Konfiguration ;;; Local Variables: *** -;;; c-basic-offset:2 *** +;;; c-basic-offset:4 *** ;;; End: *** */ diff -r 7c986b717411 -r 9f4ea66d89a3 master/slave.c --- a/master/slave.c Wed Feb 22 17:36:28 2006 +0000 +++ b/master/slave.c Thu Feb 23 09:58:50 2006 +0000 @@ -9,48 +9,431 @@ *****************************************************************************/ #include +#include #include "globals.h" #include "slave.h" +#include "frame.h" /*****************************************************************************/ /** EtherCAT-Slave-Konstruktor. - - Initialisiert einen EtherCAT-Slave. - - ACHTUNG! Dieser Konstruktor wird quasi nie aufgerufen. Bitte immer das - Makro ECAT_INIT_SLAVE() in ec_slave.h anpassen! - - @param slave Zeiger auf den zu initialisierenden Slave -*/ - -void ec_slave_init(ec_slave_t *slave) -{ - slave->base_type = 0; - slave->base_revision = 0; - slave->base_build = 0; - slave->ring_position = 0; - slave->station_address = 0; - slave->sii_vendor_id = 0; - slave->sii_product_code = 0; - slave->sii_revision_number = 0; - slave->sii_serial_number = 0; - slave->type = NULL; - slave->logical_address = 0; - slave->process_data = NULL; - slave->private_data = NULL; - slave->configure = NULL; - slave->registered = 0; - slave->domain = 0; - slave->error_reported = 0; +*/ + +void ec_slave_init(ec_slave_t *slave, /**< EtherCAT-Slave */ + ec_master_t *master /**< EtherCAT-Master */ + ) +{ + slave->master = master; + slave->base_type = 0; + slave->base_revision = 0; + slave->base_build = 0; + slave->base_fmmu_count = 0; + slave->base_sync_count = 0; + slave->ring_position = 0; + slave->station_address = 0; + slave->sii_vendor_id = 0; + slave->sii_product_code = 0; + slave->sii_revision_number = 0; + slave->sii_serial_number = 0; + slave->type = NULL; + slave->registered = 0; + slave->fmmu_count = 0; +} + +/*****************************************************************************/ + +/** + EtherCAT-Slave-Destruktor. +*/ + +void ec_slave_clear(ec_slave_t *slave /**< EtherCAT-Slave */) +{ + // Nichts freizugeben +} + +/*****************************************************************************/ + +/** + Liest alle benötigten Informationen aus einem Slave. +*/ + +int ec_slave_fetch(ec_slave_t *slave /**< EtherCAT-Slave */) +{ + ec_frame_t frame; + + // Read base data + ec_frame_init_nprd(&frame, slave->master, slave->station_address, + 0x0000, 6); + + if (unlikely(ec_frame_send_receive(&frame))) return -1; + + if (unlikely(frame.working_counter != 1)) { + printk(KERN_ERR "EtherCAT: Slave %i did not respond while reading base" + " data!\n", slave->ring_position); + return -1; + } + + slave->base_type = frame.data[0]; + slave->base_revision = frame.data[1]; + slave->base_build = frame.data[2] | (frame.data[3] << 8); + slave->base_fmmu_count = frame.data[4]; + slave->base_sync_count = frame.data[5]; + + if (slave->base_fmmu_count > EC_MAX_FMMUS) + slave->base_fmmu_count = EC_MAX_FMMUS; + + // Read identification from "Slave Information Interface" (SII) + + if (unlikely(ec_slave_sii_read(slave, 0x0008, &slave->sii_vendor_id))) { + printk(KERN_ERR "EtherCAT: Could not read SII vendor id!\n"); + return -1; + } + + if (unlikely(ec_slave_sii_read(slave, 0x000A, &slave->sii_product_code))) { + printk(KERN_ERR "EtherCAT: Could not read SII product code!\n"); + return -1; + } + + if (unlikely(ec_slave_sii_read(slave, 0x000C, + &slave->sii_revision_number))) { + printk(KERN_ERR "EtherCAT: Could not read SII revision number!\n"); + return -1; + } + + if (unlikely(ec_slave_sii_read(slave, 0x000E, + &slave->sii_serial_number))) { + printk(KERN_ERR "EtherCAT: Could not read SII serial number!\n"); + return -1; + } + + return 0; +} + +/*****************************************************************************/ + +/** + Liest Daten aus dem Slave-Information-Interface + eines EtherCAT-Slaves. + + \return 0 bei Erfolg, sonst < 0 +*/ + +int ec_slave_sii_read(ec_slave_t *slave, + /**< EtherCAT-Slave */ + unsigned short int offset, + /**< Adresse des zu lesenden SII-Registers */ + unsigned int *target + /**< Zeiger auf einen 4 Byte großen Speicher zum Ablegen + der Daten */ + ) +{ + ec_frame_t frame; + unsigned char data[10]; + unsigned int tries_left; + + // Initiate read operation + + data[0] = 0x00; + data[1] = 0x01; + data[2] = offset & 0xFF; + data[3] = (offset & 0xFF00) >> 8; + data[4] = 0x00; + data[5] = 0x00; + + ec_frame_init_npwr(&frame, slave->master, slave->station_address, 0x502, 6, + data); + + if (unlikely(ec_frame_send_receive(&frame))) return -1; + + if (unlikely(frame.working_counter != 1)) { + printk(KERN_ERR "EtherCAT: SII-read - Slave %i did not respond!\n", + slave->ring_position); + return -1; + } + + // Der Slave legt die Informationen des Slave-Information-Interface + // 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)) + { + udelay(10); + + ec_frame_init_nprd(&frame, slave->master, slave->station_address, 0x502, + 10); + + if (unlikely(ec_frame_send_receive(&frame))) return -1; + + if (unlikely(frame.working_counter != 1)) { + printk(KERN_ERR "EtherCAT: SII-read status -" + " Slave %i did not respond!\n", slave->ring_position); + return -1; + } + + if (likely((frame.data[1] & 0x81) == 0)) { + memcpy(target, frame.data + 6, 4); + break; + } + + tries_left--; + } + + if (unlikely(!tries_left)) { + printk(KERN_WARNING "EtherCAT: SSI-read. Slave %i timed out!\n", + slave->ring_position); + return -1; + } + + return 0; +} + +/*****************************************************************************/ + +/** + Bestätigt einen Fehler beim Zustandswechsel. + + FIXME Funktioniert noch nicht... +*/ + +void ec_slave_state_ack(ec_slave_t *slave, + /**< Slave, dessen Zustand geändert werden soll */ + uint8_t state + /**< Alter Zustand */ + ) +{ + ec_frame_t frame; + unsigned char data[2]; + unsigned int tries_left; + + data[0] = state | EC_ACK; + data[1] = 0x00; + + ec_frame_init_npwr(&frame, slave->master, slave->station_address, 0x0120, + 2, data); + + if (unlikely(ec_frame_send_receive(&frame) != 0)) { + printk(KERN_ERR "EtherCAT: Could no acknowledge state %02X - Unable to" + " send!\n", state); + return; + } + + if (unlikely(frame.working_counter != 1)) { + printk(KERN_ERR "EtherCAT: Could not acknowledge state %02X - Slave" + " %i did not respond!\n", state, slave->ring_position); + return; + } + + tries_left = 100; + while (likely(tries_left)) + { + udelay(10); + + ec_frame_init_nprd(&frame, slave->master, slave->station_address, + 0x0130, 2); + + if (unlikely(ec_frame_send_receive(&frame) != 0)) { + printk(KERN_ERR "EtherCAT: Could not check state acknowledgement" + " %02X - Unable to send!\n", state); + return; + } + + if (unlikely(frame.working_counter != 1)) { + printk(KERN_ERR "EtherCAT: Could not check state acknowledgement" + " %02X - Slave %i did not respond!\n", state, + slave->ring_position); + return; + } + + if (unlikely(frame.data[0] != state)) { + printk(KERN_ERR "EtherCAT: Could not acknowledge state %02X on" + " slave %i (code %02X)!\n", state, slave->ring_position, + frame.data[0]); + return; + } + + if (likely(frame.data[0] == state)) { + printk(KERN_INFO "EtherCAT: Acknowleged state %02X on slave %i.\n", + state, slave->ring_position); + return; + } + + tries_left--; + } + + if (unlikely(!tries_left)) { + printk(KERN_ERR "EtherCAT: Could not check state acknowledgement %02X" + " of slave %i - Timeout while checking!\n", state, + slave->ring_position); + return; + } +} + +/*****************************************************************************/ + +/** + Ändert den Zustand eines Slaves. + + \return 0 bei Erfolg, sonst < 0 +*/ + +int ec_slave_state_change(ec_slave_t *slave, + /**< Slave, dessen Zustand geändert werden soll */ + uint8_t state + /**< Neuer Zustand */ + ) +{ + ec_frame_t frame; + unsigned char data[2]; + unsigned int tries_left; + + data[0] = state; + data[1] = 0x00; + + ec_frame_init_npwr(&frame, slave->master, slave->station_address, 0x0120, + 2, data); + + if (unlikely(ec_frame_send_receive(&frame) != 0)) { + printk(KERN_ERR "EtherCAT: Could not set state %02X - Unable to" + " send!\n", state); + return -1; + } + + if (unlikely(frame.working_counter != 1)) { + printk(KERN_ERR "EtherCAT: Could not set state %02X - Slave %i did not" + " respond!\n", state, slave->ring_position); + return -1; + } + + tries_left = 100; + while (likely(tries_left)) + { + udelay(10); + + ec_frame_init_nprd(&frame, slave->master, slave->station_address, + 0x0130, 2); + + if (unlikely(ec_frame_send_receive(&frame) != 0)) { + printk(KERN_ERR "EtherCAT: Could not check state %02X - Unable to" + " send!\n", state); + return -1; + } + + if (unlikely(frame.working_counter != 1)) { + printk(KERN_ERR "EtherCAT: Could not check state %02X - Slave %i" + " did not respond!\n", state, slave->ring_position); + return -1; + } + + if (unlikely(frame.data[0] & 0x10)) { // State change error + printk(KERN_ERR "EtherCAT: Could not set state %02X - Slave %i" + " refused state change (code %02X)!\n", state, + slave->ring_position, frame.data[0]); + ec_slave_state_ack(slave, frame.data[0] & 0x0F); + return -1; + } + + if (likely(frame.data[0] == (state & 0x0F))) { + // State change successful + break; + } + + tries_left--; + } + + if (unlikely(!tries_left)) { + printk(KERN_ERR "EtherCAT: Could not check state %02X of slave %i -" + " Timeout while checking!\n", state, + slave->ring_position); + return -1; + } + + return 0; +} + +/*****************************************************************************/ + +/** + Merkt eine FMMU-Konfiguration vor. + + Die FMMU wird so konfiguriert, dass sie den gesamten Datenbereich des + entsprechenden Sync-Managers abdeckt. Für jede Domäne werden separate + FMMUs konfiguriert. + + Wenn die entsprechende FMMU bereits konfiguriert ist, wird dies als + Erfolg zurückgegeben. + + \return 0 bei Erfolg, sonst < 0 +*/ + +int ec_slave_set_fmmu(ec_slave_t *slave, /**< EtherCAT-Slave */ + const ec_domain_t *domain, /**< Domäne */ + const ec_sync_t *sync /**< Sync-Manager */ + ) +{ + unsigned int i; + + // FMMU schon vorgemerkt? + for (i = 0; i < slave->fmmu_count; i++) + if (slave->fmmus[i].domain == domain && slave->fmmus[i].sync == sync) + return 0; + + if (slave->fmmu_count >= slave->base_fmmu_count) { + printk(KERN_ERR "EtherCAT: Slave %i supports only %i FMMUs.\n", + slave->ring_position, slave->base_fmmu_count); + return -1; + } + + slave->fmmus[slave->fmmu_count].domain = domain; + slave->fmmus[slave->fmmu_count].sync = sync; + slave->fmmus[slave->fmmu_count].logical_start_address = 0; + slave->fmmu_count++; + slave->registered = 1; + + return 0; +} + +/*****************************************************************************/ + +/** + Gibt alle Informationen über einen EtherCAT-Slave aus. +*/ + +void ec_slave_print(const ec_slave_t *slave /**< EtherCAT-Slave */) +{ + printk(KERN_INFO "--- EtherCAT slave information ---\n"); + + if (slave->type) { + printk(KERN_INFO " Vendor \"%s\", Product \"%s\": %s\n", + slave->type->vendor_name, slave->type->product_name, + slave->type->description); + } + else { + printk(KERN_INFO " *** This slave has no type information! ***\n"); + } + + printk(KERN_INFO " Ring position: %i, Station address: 0x%04X\n", + slave->ring_position, slave->station_address); + + printk(KERN_INFO " Base information:\n"); + printk(KERN_INFO " Type %u, Revision %i, Build %i\n", + slave->base_type, slave->base_revision, slave->base_build); + printk(KERN_INFO " Supported FMMUs: %i, Sync managers: %i\n", + slave->base_fmmu_count, slave->base_sync_count); + + printk(KERN_INFO " Slave information interface:\n"); + printk(KERN_INFO " Vendor-ID: 0x%08X, Product code: 0x%08X\n", + slave->sii_vendor_id, slave->sii_product_code); + printk(KERN_INFO " Revision number: 0x%08X, Serial number: 0x%08X\n", + slave->sii_revision_number, slave->sii_serial_number); } /*****************************************************************************/ /* Emacs-Konfiguration ;;; Local Variables: *** -;;; c-basic-offset:2 *** +;;; c-basic-offset:4 *** ;;; End: *** */ diff -r 7c986b717411 -r 9f4ea66d89a3 master/slave.h --- a/master/slave.h Wed Feb 22 17:36:28 2006 +0000 +++ b/master/slave.h Thu Feb 23 09:58:50 2006 +0000 @@ -15,12 +15,68 @@ /*****************************************************************************/ -// ec_slave_t ist in EtherCAT_rt.h ... +/** + FMMU-Konfiguration. +*/ + +typedef struct +{ + const ec_domain_t *domain; + const ec_sync_t *sync; + uint32_t logical_start_address; +} +ec_fmmu_t; /*****************************************************************************/ -// Slave construction and deletion -void ec_slave_init(ec_slave_t *); +/** + EtherCAT-Slave +*/ + +struct ec_slave +{ + ec_master_t *master; /**< EtherCAT-Master, zu dem der Slave gehört. */ + + // Addresses + uint16_t ring_position; /**< Position des Slaves im Bus */ + uint16_t station_address; /**< Konfigurierte Slave-Adresse */ + + // Base data + uint8_t base_type; /**< Slave-Typ */ + uint8_t base_revision; /**< Revision */ + uint16_t base_build; /**< Build-Nummer */ + uint16_t base_fmmu_count; /**< Anzahl unterstützter FMMUs */ + uint16_t base_sync_count; /**< Anzahl unterstützter Sync-Manager */ + + // Slave information interface + uint32_t sii_vendor_id; /**< Identifikationsnummer des Herstellers */ + uint32_t sii_product_code; /**< Herstellerspezifischer Produktcode */ + uint32_t sii_revision_number; /**< Revisionsnummer */ + uint32_t sii_serial_number; /**< Seriennummer der Klemme */ + + const ec_slave_type_t *type; /**< Zeiger auf die Beschreibung + des Slave-Typs */ + + uint8_t registered; /**< Der Slave wurde registriert */ + + ec_fmmu_t fmmus[EC_MAX_FMMUS]; /**< FMMU-Konfigurationen */ + uint8_t fmmu_count; /**< Wieviele FMMUs schon benutzt sind. */ +}; + +/*****************************************************************************/ + +// Slave construction/destruction +void ec_slave_init(ec_slave_t *, ec_master_t *); +void ec_slave_clear(ec_slave_t *); + +// Slave control +int ec_slave_fetch(ec_slave_t *); +int ec_slave_sii_read(ec_slave_t *, unsigned short, unsigned int *); +int ec_slave_state_change(ec_slave_t *, uint8_t); +int ec_slave_set_fmmu(ec_slave_t *, const ec_domain_t *, const ec_sync_t *); + +// Misc +void ec_slave_print(const ec_slave_t *); /*****************************************************************************/ @@ -28,6 +84,6 @@ /* Emacs-Konfiguration ;;; Local Variables: *** -;;; c-basic-offset:2 *** +;;; c-basic-offset:4 *** ;;; End: *** */ diff -r 7c986b717411 -r 9f4ea66d89a3 master/types.c --- a/master/types.c Wed Feb 22 17:36:28 2006 +0000 +++ b/master/types.c Thu Feb 23 09:58:50 2006 +0000 @@ -15,134 +15,148 @@ /*****************************************************************************/ -/* - Konfigurationen der Sync-Manager - - Byte 1-2: Physical Start Address - Byte 3-4: Data Length - Byte 5: Control Byte - Byte 6: Status Byte (read only) - Byte 7-8: Enable -*/ - -unsigned char sm0_multi[] = {0x00, 0x18, 0xF6, 0x00, 0x26, 0x00, 0x01, 0x00}; -unsigned char sm1_multi[] = {0xF6, 0x18, 0xF6, 0x00, 0x22, 0x00, 0x01, 0x00}; - -unsigned char sm0_1014[] = {0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00}; - -unsigned char sm0_20xx[] = {0x00, 0x0F, 0x01, 0x00, 0x46, 0x00, 0x01, 0x00}; - -unsigned char sm2_31xx[] = {0x00, 0x10, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00}; -unsigned char sm3_31xx[] = {0x00, 0x11, 0x06, 0x00, 0x20, 0x00, 0x01, 0x00}; - -unsigned char sm2_41xx[] = {0x00, 0x10, 0x04, 0x00, 0x24, 0x00, 0x01, 0x00}; - -unsigned char sm2_5001[] = {0x00, 0x10, 0x04, 0x00, 0x24, 0x00, 0x01, 0x00}; -unsigned char sm3_5001[] = {0x00, 0x11, 0x05, 0x00, 0x20, 0x00, 0x01, 0x00}; - -unsigned char sm2_5101[] = {0x00, 0x10, 0x03, 0x00, 0x24, 0x00, 0x01, 0x00}; -unsigned char sm3_5101[] = {0x00, 0x11, 0x05, 0x00, 0x20, 0x00, 0x01, 0x00}; - -/* - Konfigurationen der Memory-Management-Units - - Byte 1-4: Logical Start Address (is set later) - Byte 5-6: Length - Byte 7: Logical start bit - Byte 8: Logical end bit - Byte 9-10: Physical start address - Byte 11: Physical start bit - Byte 12: Direction (1: in, 2: out) - Byte 13-14: Channel enable - Byte 15-16: Reserved -*/ - -unsigned char fmmu0_1014[] = {0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x07, - 0x00, 0x10, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00}; - -unsigned char fmmu0_20xx[] = {0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x07, - 0x00, 0x0F, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00}; - -unsigned char fmmu0_31xx[] = {0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x07, - 0x00, 0x11, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00}; - -unsigned char fmmu0_41xx[] = {0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x07, - 0x00, 0x10, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00}; - -unsigned char fmmu0_5001[] = {0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x07, - 0x00, 0x11, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00}; - -unsigned char fmmu0_5101[] = {0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x07, - 0x00, 0x11, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00}; +const ec_sync_t mailbox_sm0 = {0x1800, 246, 0x26, {NULL}}; +const ec_sync_t mailbox_sm1 = {0x18F6, 246, 0x22, {NULL}}; /*****************************************************************************/ /* Klemmen-Objekte */ -ec_slave_type_t Beckhoff_EK1100 = -{ - "Beckhoff", "EK1100", "Bus Coupler", - EC_NOSYNC_SLAVE, NULL, NULL, NULL, NULL, NULL, 0 +/*****************************************************************************/ + +const ec_slave_type_t Beckhoff_EK1100 = { + "Beckhoff", "EK1100", "Bus Coupler", EC_NOSYNC_SLAVE, + {NULL} // Keine Sync-Manager }; -ec_slave_type_t Beckhoff_EK1110 = -{ - "Beckhoff", "EK1110", "Extension terminal", - EC_NOSYNC_SLAVE, NULL, NULL, NULL, NULL, NULL, 0 +/*****************************************************************************/ + +const ec_slave_type_t Beckhoff_EK1110 = { + "Beckhoff", "EK1110", "Extension terminal", EC_NOSYNC_SLAVE, + {NULL} // Keine Sync-Manager }; -ec_slave_type_t Beckhoff_EL1014 = -{ - "Beckhoff", "EL1014", "4x Digital Input", - EC_SIMPLE_SLAVE, sm0_1014, NULL, NULL, NULL, fmmu0_1014, 1 +/*****************************************************************************/ + +const ec_field_t el1014_in = {ec_ipvalue, 1}; + +const ec_sync_t el1014_sm0 = { // Inputs + 0x1000, 1, 0x00, + {&el1014_in, NULL} }; -ec_slave_type_t Beckhoff_EL2004 = -{ - "Beckhoff", "EL2004", "4x Digital Output", - EC_SIMPLE_SLAVE, sm0_20xx, NULL, NULL, NULL, fmmu0_20xx, 1 +const ec_slave_type_t Beckhoff_EL1014 = { + "Beckhoff", "EL1014", "4x Digital Input", EC_SIMPLE_SLAVE, + {&el1014_sm0, NULL} }; -ec_slave_type_t Beckhoff_EL2032 = -{ - "Beckhoff", "EL2032", "2x Digital Output (2A)", - EC_SIMPLE_SLAVE, sm0_20xx, NULL, NULL, NULL, fmmu0_20xx, 1 +/*****************************************************************************/ + +const ec_field_t el20XX_out = {ec_opvalue, 1}; + +const ec_sync_t el20XX_sm0 = { + 0x0F00, 1, 0x46, + {&el20XX_out, NULL} }; -ec_slave_type_t Beckhoff_EL3102 = -{ - "Beckhoff", "EL3102", "2x Analog Input diff.", - EC_MAILBOX_SLAVE, sm0_multi, sm1_multi, sm2_31xx, sm3_31xx, fmmu0_31xx, 6 +const ec_slave_type_t Beckhoff_EL2004 = { + "Beckhoff", "EL2004", "4x Digital Output", EC_SIMPLE_SLAVE, + {&el20XX_sm0, NULL} }; -ec_slave_type_t Beckhoff_EL3162 = -{ - "Beckhoff", "EL3162", "2x Analog Input", - EC_MAILBOX_SLAVE, sm0_multi, sm1_multi, sm2_31xx, sm3_31xx, fmmu0_31xx, 6 +const ec_slave_type_t Beckhoff_EL2032 = { + "Beckhoff", "EL2032", "2x Digital Output (2A)", EC_SIMPLE_SLAVE, + {&el20XX_sm0, NULL} }; -ec_slave_type_t Beckhoff_EL4102 = -{ - "Beckhoff", "EL4102", "2x Analog Output", - EC_MAILBOX_SLAVE, sm0_multi, sm1_multi, sm2_41xx, NULL, fmmu0_41xx, 4 +/*****************************************************************************/ + +const ec_field_t el31X2_st1 = {ec_status, 1}; +const ec_field_t el31X2_ip1 = {ec_ipvalue, 2}; +const ec_field_t el31X2_st2 = {ec_status, 1}; +const ec_field_t el31X2_ip2 = {ec_ipvalue, 2}; + +const ec_sync_t el31X2_sm2 = { + 0x1000, 4, 0x24, + {NULL} }; -ec_slave_type_t Beckhoff_EL4132 = -{ - "Beckhoff", "EL4132", "2x Analog Output diff.", - EC_MAILBOX_SLAVE, sm0_multi, sm1_multi, sm2_41xx, NULL, fmmu0_41xx, 4 +const ec_sync_t el31X2_sm3 = { + 0x1100, 6, 0x20, + {&el31X2_st1, &el31X2_ip1, &el31X2_st2, &el31X2_ip2, NULL} }; -ec_slave_type_t Beckhoff_EL5001 = -{ - "Beckhoff", "EL5001", "SSI-Interface", - EC_MAILBOX_SLAVE, sm0_multi, sm1_multi, sm2_5001, sm3_5001, fmmu0_5001, 5 +const ec_slave_type_t Beckhoff_EL3102 = { + "Beckhoff", "EL3102", "2x Analog Input diff.", EC_MAILBOX_SLAVE, + {&mailbox_sm0, &mailbox_sm1, &el31X2_sm2, &el31X2_sm2, NULL} }; -ec_slave_type_t Beckhoff_EL5101 = +const ec_slave_type_t Beckhoff_EL3162 = { + "Beckhoff", "EL3102", "2x Analog Input", EC_MAILBOX_SLAVE, + {&mailbox_sm0, &mailbox_sm1, &el31X2_sm2, &el31X2_sm2, NULL} +}; + +/*****************************************************************************/ + +const ec_field_t el41X2_op = {ec_opvalue, 2}; + +const ec_sync_t el41X2_sm2 = { + 0x1000, 4, 0x24, + {&el41X2_op, &el41X2_op, NULL} +}; + +const ec_slave_type_t Beckhoff_EL4102 = { + "Beckhoff", "EL4102", "2x Analog Output", EC_MAILBOX_SLAVE, + {&mailbox_sm0, &mailbox_sm1, &el41X2_sm2, NULL} +}; + +const ec_slave_type_t Beckhoff_EL4132 = { + "Beckhoff", "EL4132", "2x Analog Output diff.", EC_MAILBOX_SLAVE, + {&mailbox_sm0, &mailbox_sm1, &el41X2_sm2, NULL} +}; + +/*****************************************************************************/ + +const ec_field_t el5001_st = {ec_status, 1}; +const ec_field_t el5001_ip = {ec_ipvalue, 4}; + +const ec_sync_t el5001_sm2 = { + 0x1000, 4, 0x24, + {NULL} +}; + +const ec_sync_t el5001_sm3 = { + 0x1100, 5, 0x20, + {&el5001_st, &el5001_ip, NULL} +}; + +const ec_slave_type_t Beckhoff_EL5001 = { + "Beckhoff", "EL5001", "SSI-Interface", EC_MAILBOX_SLAVE, + {&mailbox_sm0, &mailbox_sm1, &el5001_sm2, &el5001_sm3, NULL} +}; + +/*****************************************************************************/ + +const ec_field_t el5101_ct = {ec_control, 1}; +const ec_field_t el5101_op = {ec_opvalue, 2}; +const ec_field_t el5101_st = {ec_status, 1}; +const ec_field_t el5101_ip = {ec_ipvalue, 2}; +const ec_field_t el5101_la = {ec_ipvalue, 2}; + +const ec_sync_t el5101_sm2 = { + 0x1000, 3, 0x24, + {&el5101_ct, &el5101_op, NULL} +}; + +const ec_sync_t el5101_sm3 = { + 0x1100, 5, 0x20, + {&el5101_st, &el5101_ip, &el5101_la, NULL} +}; + +const ec_slave_type_t Beckhoff_EL5101 = { - "Beckhoff", "EL5101", "Incremental Encoder Interface", - EC_MAILBOX_SLAVE, sm0_multi, sm1_multi, sm2_5101, sm3_5101, fmmu0_5101, 5 + "Beckhoff", "EL5101", "Incremental Encoder Interface", EC_MAILBOX_SLAVE, + {&mailbox_sm0, &mailbox_sm1, &el5101_sm2, &el5101_sm3, NULL} }; /*****************************************************************************/ @@ -167,10 +181,14 @@ {0x00000002, 0x10063052, &Beckhoff_EL4102}, {0x00000002, 0x10243052, &Beckhoff_EL4132}, {0x00000002, 0x13893052, &Beckhoff_EL5001}, - {0x00000002, 0x13ED3052, &Beckhoff_EL5101} + {0x00000002, 0x13ED3052, &Beckhoff_EL5101}, + {} }; -unsigned int slave_ident_count = sizeof(slave_idents) - / sizeof(ec_slave_ident_t); +/*****************************************************************************/ -/*****************************************************************************/ +/* Emacs-Konfiguration +;;; Local Variables: *** +;;; c-basic-offset:4 *** +;;; End: *** +*/ diff -r 7c986b717411 -r 9f4ea66d89a3 master/types.h --- a/master/types.h Wed Feb 22 17:36:28 2006 +0000 +++ b/master/types.h Thu Feb 23 09:58:50 2006 +0000 @@ -11,10 +11,17 @@ #ifndef _EC_TYPES_H_ #define _EC_TYPES_H_ +#include + #include "../include/EtherCAT_rt.h" /*****************************************************************************/ +#define EC_MAX_FIELDS 10 +#define EC_MAX_SYNC 16 + +/*****************************************************************************/ + /** Features eines EtherCAT-Slaves. @@ -32,6 +39,34 @@ /*****************************************************************************/ /** + Prozessdatenfeld. +*/ + +typedef struct +{ + ec_field_type_t type; + unsigned int size; +} +ec_field_t; + +/*****************************************************************************/ + +/** + Sync-Manager. +*/ + +typedef struct +{ + uint16_t physical_start_address; + uint16_t size; + uint8_t control_byte; + const ec_field_t *fields[EC_MAX_FIELDS]; +} +ec_sync_t; + +/*****************************************************************************/ + +/** Beschreibung eines EtherCAT-Slave-Typs. Diese Beschreibung dient zur Konfiguration einer bestimmten @@ -39,28 +74,16 @@ Slave-internen Sync-Manager und FMMU's. */ -struct ec_slave_type +typedef struct ec_slave_type { const char *vendor_name; /**< Name des Herstellers */ const char *product_name; /**< Name des Slaves-Typs */ - const char *product_desc; /**< Genauere Beschreibung des Slave-Typs */ - + const char *description; /**< Genauere Beschreibung des Slave-Typs */ ec_slave_features_t features; /**< Features des Slave-Typs */ - - const unsigned char *sm0; /**< Konfigurationsdaten des - ersten Sync-Managers */ - const unsigned char *sm1; /**< Konfigurationsdaten des - zweiten Sync-Managers */ - const unsigned char *sm2; /**< Konfigurationsdaten des - dritten Sync-Managers */ - const unsigned char *sm3; /**< Konfigurationsdaten des - vierten Sync-Managers */ - - const unsigned char *fmmu0; /**< Konfigurationsdaten - der ersten FMMU */ - - unsigned int process_data_size; /**< Länge der Prozessdaten in Bytes */ -}; + const ec_sync_t *sync_managers[EC_MAX_SYNC]; /**< Sync-Manager + Konfigurationen */ +} +ec_slave_type_t; /*****************************************************************************/ @@ -81,9 +104,13 @@ extern ec_slave_ident_t slave_idents[]; /**< Statisches Array der Slave-Identifikationen */ -extern unsigned int slave_ident_count; /**< Anzahl der vorhandenen - Slave-Identifikationen */ /*****************************************************************************/ #endif + +/* Emacs-Konfiguration +;;; Local Variables: *** +;;; c-basic-offset:4 *** +;;; End: *** +*/ diff -r 7c986b717411 -r 9f4ea66d89a3 mini/mini.c --- a/mini/mini.c Wed Feb 22 17:36:28 2006 +0000 +++ b/mini/mini.c Thu Feb 23 09:58:50 2006 +0000 @@ -17,48 +17,51 @@ /*****************************************************************************/ -ec_master_t *master = NULL; -ec_slave_t *s_in, *s_out, *s_ssi; +#define ABTASTFREQUENZ 1000 struct timer_list timer; -ec_slave_init_t slaves[] = { - // Zeiger, Index, Herstellername, Produktname, Domäne - { &s_in, "1", "Beckhoff", "EL3102", 1 }, - { &s_out, "2", "Beckhoff", "EL2004", 1 }, - { &s_ssi, "3", "Beckhoff", "EL5001", 1 } +/*****************************************************************************/ + +// EtherCAT +ec_master_t *master = NULL; +ec_domain_t *domain1 = NULL; + +// Prozessdaten +uint8_t *dig_out1; +uint16_t *ssi_value; +uint16_t *inc_value; + +uint32_t angle0; + +ec_field_init_t domain1_fields[] = { + {(void **) &dig_out1, "2", "Beckhoff", "EL2004", ec_opvalue, 0, 1}, + {(void **) &ssi_value, "3", "Beckhoff", "EL5001", ec_ipvalue, 0, 1}, + {(void **) &inc_value, "0:4", "Beckhoff", "EL5101", ec_ipvalue, 0, 1}, + {} }; -#define SLAVE_COUNT (sizeof(slaves) / sizeof(ec_slave_init_t)) - /*****************************************************************************/ void run(unsigned long data) { - static unsigned int counter; - - // Klemmen-IO - EC_WRITE_EL20XX(s_out, 3, EC_READ_EL31XX(s_in, 0) < 0); - - if (!counter) { - EtherCAT_rt_debug_level(master, 2); - } + static unsigned int counter = 0; // Prozessdaten lesen und schreiben - EtherCAT_rt_domain_xio(master, 1, 100); + EtherCAT_rt_domain_xio(domain1); + + angle0 = (uint32_t) *inc_value; if (counter) { counter--; } else { - EtherCAT_rt_debug_level(master, 0); - printk("SSI status=%X value=%u\n", - EC_READ_EL5001_STATE(s_ssi), EC_READ_EL5001_VALUE(s_ssi)); - counter = 1000; + counter = ABTASTFREQUENZ; + printk(KERN_INFO "angle0 = %i\n", angle0); } // Timer neu starten - timer.expires += HZ / 1000; + timer.expires += HZ / ABTASTFREQUENZ; add_timer(&timer); } @@ -66,41 +69,52 @@ int __init init_mini_module(void) { + const ec_field_init_t *field; + printk(KERN_INFO "=== Starting Minimal EtherCAT environment... ===\n"); if ((master = EtherCAT_rt_request_master(0)) == NULL) { - printk(KERN_ERR "EtherCAT master 0 not available!\n"); + printk(KERN_ERR "Error requesting master 0!\n"); goto out_return; } - if (EtherCAT_rt_register_slave_list(master, slaves, SLAVE_COUNT)) { - printk(KERN_ERR "Could not register slaves!\n"); + EtherCAT_rt_master_print(master); + + printk(KERN_INFO "Registering domain...\n"); + + if (!(domain1 = EtherCAT_rt_master_register_domain(master, ec_sync, 100))) + { + printk(KERN_ERR "EtherCAT: Could not register domain!\n"); goto out_release_master; } - printk("Activating all EtherCAT slaves.\n"); + printk(KERN_INFO "Registering domain fields...\n"); - if (EtherCAT_rt_activate_slaves(master)) { - printk(KERN_ERR "EtherCAT: Could not activate slaves!\n"); - goto out_release_master; + 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 "EtherCAT: Could not register field!\n"); + goto out_release_master; + } } - printk("Configuring EtherCAT slaves.\n"); + printk(KERN_INFO "Activating master...\n"); - if (EtherCAT_rt_canopen_sdo_write(master, s_ssi, 0x4067, 0, 2, 2)) { - printk(KERN_ERR "EtherCAT: Could not set SSI baud rate!\n"); - goto out_release_master; - } - - if (EtherCAT_rt_canopen_sdo_write(master, s_ssi, 0x4061, 4, 1, 1)) { - printk(KERN_ERR "EtherCAT: Could not set SSI feature bit!\n"); + if (EtherCAT_rt_master_activate(master)) { + printk(KERN_ERR "EtherCAT: Could not activate master!\n"); goto out_release_master; } printk("Starting cyclic sample thread.\n"); init_timer(&timer); - timer.function = run; timer.expires = jiffies + 10; // Das erste Mal sofort feuern add_timer(&timer); @@ -126,9 +140,9 @@ { del_timer_sync(&timer); - printk(KERN_INFO "Deactivating slaves.\n"); + printk(KERN_INFO "Deactivating master...\n"); - EtherCAT_rt_deactivate_slaves(master); + EtherCAT_rt_master_deactivate(master); EtherCAT_rt_release_master(master); } @@ -139,7 +153,7 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR ("Florian Pose "); -MODULE_DESCRIPTION ("Minimal EtherCAT environment"); +MODULE_DESCRIPTION ("EtherCAT minimal test environment"); module_init(init_mini_module); module_exit(cleanup_mini_module); diff -r 7c986b717411 -r 9f4ea66d89a3 rt/Makefile --- a/rt/Makefile Wed Feb 22 17:36:28 2006 +0000 +++ b/rt/Makefile Thu Feb 23 09:58:50 2006 +0000 @@ -14,7 +14,6 @@ obj-m := msr_modul.o msr_modul-objs := msr_module.o \ - msr_jitter.o \ rt_lib/msr-core/msr_lists.o \ rt_lib/msr-core/msr_main.o \ rt_lib/msr-core/msr_charbuf.o \ @@ -24,7 +23,9 @@ rt_lib/msr-core/msr_proc.o \ rt_lib/msr-core/msr_error_reg.o \ rt_lib/msr-utils/msr_utils.o \ + rt_lib/msr-utils/msr_time.o \ rt_lib/msr-math/msr_base64.o \ + rt_lib/msr-math/msr_hex_bin.o \ libm.o EXTRA_CFLAGS := -I $(src)/rt_lib/msr-include -D_SIMULATION \ diff -r 7c986b717411 -r 9f4ea66d89a3 rt/msr_jitter.c --- a/rt/msr_jitter.c Wed Feb 22 17:36:28 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,129 +0,0 @@ -/****************************************************************************** - * - * msr_jitter.c - * - * Autor: Wilhelm Hagemeister - * - * (C) Copyright IgH 2002 - * Ingenieurgemeinschaft IgH - * Heinz-Bäcker Str. 34 - * D-45356 Essen - * Tel.: +49 201/61 99 31 - * Fax.: +49 201/61 98 36 - * E-mail: hm@igh-essen.com - * - * $Id$ - * - *****************************************************************************/ - -#ifndef __KERNEL__ -# define __KERNEL__ -#endif -#ifndef MODULE -# define MODULE -#endif - -#include -#include -#include -#include -#include /* maschine-specific registers */ -#include /* fuer HZ */ - -#include -#include "msr_jitter.h" - -/*--includes-----------------------------------------------------------------*/ - -/*--external functions-------------------------------------------------------*/ - -/*--external data------------------------------------------------------------*/ - -/*--public data--------------------------------------------------------------*/ - -/*--local data---------------------------------------------------------------*/ - -#define NUMCLASSES 16 - -static int jittime[NUMCLASSES]={0,1,2,5,10,20,50,100,200,500, - 1000,2000,5000,10000,20000,50000}; //in usec -static int jitcount[NUMCLASSES]; -static double jitpercent[NUMCLASSES]; -static unsigned int tcount = 1; - -static void msr_jit_read(void) -{ - int i; - for(i=0;i100) { - jitpercent[i] = jitcount[i]*100.0/tcount; - } - } -} - -void msr_jitter_init(void) -{ - msr_reg_int_list("/Taskinfo/Jitter/Classes","usec", - &jittime[0],MSR_R,NUMCLASSES,NULL,NULL,NULL); - msr_reg_int_list("/Taskinfo/Jitter/Count","", - &jitcount[0],MSR_R,NUMCLASSES,NULL,NULL,NULL); - msr_reg_dbl_list("/Taskinfo/Jitter/percent","%", - &jitpercent[0],MSR_R,NUMCLASSES,NULL,NULL,&msr_jit_read); -} - -/****************************************************************************** - * - * Function: msr_jitter_run - * - * Beschreibung: - * - * - * Parameter: Zeiger auf msr_data - * - * Rückgabe: - * - * Status: exp - * - *****************************************************************************/ - -void msr_jitter_run(unsigned int hz) { - - int i,hit; - static int firstrun = 1; - static unsigned long k,j = 0; - unsigned int dt,jitter; - - - rdtscl(k); - - tcount++; - - //Zeitabstand zwischen zwei Interrupts in usec - - dt = ((unsigned long)(100000/HZ)*((unsigned long)(k-j))) - /(current_cpu_data.loops_per_jiffy/10); - - jitter = (unsigned int)abs((int)dt-(int)1000000/hz); - //jitter errechnet zum Sollabtastrate - - //in die Klassen einsortieren - if(!firstrun) { //das erste mal nicht einsortieren - hit = 0; - for(i=0;i=jittime[i] && jitter #include +#include +#include // RT_lib #include @@ -28,105 +30,62 @@ #include #include #include +#include #include "msr_param.h" -#include "msr_jitter.h" // EtherCAT #include "../include/EtherCAT_rt.h" #include "../include/EtherCAT_si.h" // Defines/Makros -#define TSC2US(T1, T2) ((T2 - T1) * 1000UL / cpu_khz) #define HZREDUCTION (MSR_ABTASTFREQUENZ / HZ) /*****************************************************************************/ /* Globale Variablen */ -// RT_lib -extern struct timeval process_time; -struct timeval msr_time_increment; // Increment per Interrupt - // Adeos static struct ipipe_domain this_domain; static struct ipipe_sysinfo sys_info; // EtherCAT ec_master_t *master = NULL; -ec_slave_t *s_in1, *s_out1, *s_ssi, *s_inc; - -uint16_t angle0; - -ec_slave_init_t slaves[] = { - {&s_in1, "1", "Beckhoff", "EL3102", 0}, - {&s_out1, "2", "Beckhoff", "EL2004", 0}, - {&s_ssi, "3", "Beckhoff", "EL5001", 0}, - {&s_inc, "0:4", "Beckhoff", "EL5101", 0} +ec_domain_t *domain1 = NULL; + +// Prozessdaten +uint8_t *dig_out1; +uint16_t *ssi_value; +uint16_t *inc_value; + +uint32_t angle0; + +ec_field_init_t domain1_fields[] = { + {(void **) &dig_out1, "2", "Beckhoff", "EL2004", ec_opvalue, 0, 1}, + {(void **) &ssi_value, "3", "Beckhoff", "EL5001", ec_ipvalue, 0, 1}, + {(void **) &inc_value, "0:4", "Beckhoff", "EL5101", ec_ipvalue, 0, 1}, + {} }; -#define SLAVE_COUNT (sizeof(slaves) / sizeof(ec_slave_init_t)) - -/****************************************************************************** - * - * Function: msr_controller_run() - * - *****************************************************************************/ +/*****************************************************************************/ static void msr_controller_run(void) { - static unsigned int counter = 0; - - msr_jitter_run(MSR_ABTASTFREQUENZ); - - EC_WRITE_EL20XX(s_out1, 3, EC_READ_EL31XX(s_in1, 0) < 0); - - if (!counter) { - EtherCAT_rt_debug_level(master, 2); - } - // Prozessdaten lesen und schreiben - EtherCAT_rt_domain_xio(master, 0, 40); - - if (counter) { - counter--; - } - else { - EtherCAT_rt_debug_level(master, 0); - printk("SSI status=0x%X value=%u\n", - EC_READ_EL5001_STATE(s_ssi), EC_READ_EL5001_VALUE(s_ssi)); - printk("INC status=0x%X value=%u\n", - EC_READ_EL5101_STATE(s_inc), EC_READ_EL5101_VALUE(s_inc)); - - counter = MSR_ABTASTFREQUENZ * 5; - } - - angle0 = EC_READ_EL5101_VALUE(s_inc); -} - -/****************************************************************************** - * - * Function: msr_run(_interrupt) - * - * Beschreibung: Routine wird zyklisch im Timerinterrupt ausgeführt - * (hier muß alles rein, was Echtzeit ist ...) - * - * Parameter: Zeiger auf msr_data - * - * Rückgabe: - * - * Status: exp - * - *****************************************************************************/ + EtherCAT_rt_domain_xio(domain1); + + angle0 = (uint32_t) *inc_value; +} + +/*****************************************************************************/ void msr_run(unsigned irq) { static int counter = 0; - timeval_add(&process_time, &process_time, &msr_time_increment); MSR_ADEOS_INTERRUPT_CODE(msr_controller_run(); msr_write_kanal_list();); - ipipe_control_irq(irq,0,IPIPE_ENABLE_MASK); //Interrupt bestŽätigen - if (counter++ > HZREDUCTION) { - ipipe_propagate_irq(irq); //und weiterreichen + ipipe_control_irq(irq, 0, IPIPE_ENABLE_MASK); // Interrupt bestŽätigen + if (++counter >= HZREDUCTION) { + ipipe_propagate_irq(irq); // und weiterreichen counter = 0; } } @@ -144,75 +103,78 @@ ipipe_tune_timer(1000000000UL / MSR_ABTASTFREQUENZ, 0); } -/****************************************************************************** - * - * Function: msr_register_channels - * - * Beschreibung: KanŽäle registrieren - * - * Parameter: - * - * RŽückgabe: - * - * Status: exp - * - *****************************************************************************/ +/*****************************************************************************/ int msr_globals_register(void) { - //msr_reg_kanal("/value", "V", &value, TDBL); - //msr_reg_kanal("/dig1", "", &dig1, TINT); - msr_reg_kanal("/angle0", "", &angle0, TINT); + msr_reg_kanal("/angle0", "", &angle0, TUINT); return 0; } -/****************************************************************************** - * the init/clean material - *****************************************************************************/ +/*****************************************************************************/ int __init init_rt_module(void) { struct ipipe_domain_attr attr; //ipipe + const ec_field_init_t *field; // Als allererstes die RT-lib initialisieren - if (msr_rtlib_init(1,MSR_ABTASTFREQUENZ,10,&msr_globals_register) < 0) { + if (msr_rtlib_init(1, MSR_ABTASTFREQUENZ, 10, &msr_globals_register) < 0) { msr_print_warn("msr_modul: can't initialize rtlib!"); goto out_return; } - msr_jitter_init(); - - printk(KERN_INFO "=== Starting EtherCAT environment... ===\n"); - if ((master = EtherCAT_rt_request_master(0)) == NULL) { printk(KERN_ERR "Error requesting master 0!\n"); goto out_msr_cleanup; } - if (EtherCAT_rt_register_slave_list(master, slaves, SLAVE_COUNT)) { - printk(KERN_ERR "EtherCAT: Could not register slaves!\n"); - goto out_release_master; - } - - if (EtherCAT_rt_activate_slaves(master) < 0) { - printk(KERN_ERR "EtherCAT: Could not activate slaves!\n"); - goto out_release_master; - } - - if (EtherCAT_rt_canopen_sdo_write(master, s_ssi, 0x4067, 0, 1, 2)) { + EtherCAT_rt_master_print(master); + + printk(KERN_INFO "Registering domain...\n"); + + if (!(domain1 = 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 "EtherCAT: Could not register field!\n"); + goto out_release_master; + } + } + + printk(KERN_INFO "Activating master...\n"); + + if (EtherCAT_rt_master_activate(master)) { + printk(KERN_ERR "EtherCAT: Could not activate master!\n"); + goto out_release_master; + } + +#if 0 + if (EtherCAT_rt_canopen_sdo_write(master, "0:4", 0x4067, 0, 1, 2)) { printk(KERN_ERR "EtherCAT: Could not set SSI baud rate!\n"); goto out_release_master; } - if (EtherCAT_rt_canopen_sdo_write(master, s_ssi, 0x4061, 4, 1, 1)) { + if (EtherCAT_rt_canopen_sdo_write(master, "0:4", 0x4061, 4, 1, 1)) { printk(KERN_ERR "EtherCAT: Could not set SSI feature bit!\n"); goto out_release_master; } - - do_gettimeofday(&process_time); - msr_time_increment.tv_sec = 0; - msr_time_increment.tv_usec = (unsigned int) (1000000 / MSR_ABTASTFREQUENZ); +#endif ipipe_init_attr(&attr); attr.name = "IPIPE-MSR-MODULE"; @@ -245,10 +207,10 @@ { printk(KERN_INFO "=== Stopping EtherCAT environment... ===\n"); - printk(KERN_INFO "Deactivating slaves.\n"); - - if (EtherCAT_rt_deactivate_slaves(master) < 0) { - printk(KERN_WARNING "Warning - Could not deactivate slaves!\n"); + printk(KERN_INFO "Deactivating master...\n"); + + if (EtherCAT_rt_master_deactivate(master) < 0) { + printk(KERN_WARNING "Warning - Could not deactivate master!\n"); } EtherCAT_rt_release_master(master); @@ -262,8 +224,8 @@ /*****************************************************************************/ MODULE_LICENSE("GPL"); -MODULE_AUTHOR ("Wilhelm Hagemeister "); -MODULE_DESCRIPTION ("EtherCAT test environment"); +MODULE_AUTHOR ("Florian Pose "); +MODULE_DESCRIPTION ("EtherCAT real-time test environment"); module_init(init_rt_module); module_exit(cleanup_rt_module);