MERGE branches/async 222:233 -> trunk (Kommando-Warteschlangen).

This commit is contained in:
Florian Pose
2006-03-06 15:12:34 +00:00
parent 11d861522b
commit b38ffbe720
22 changed files with 1251 additions and 1237 deletions

View File

@@ -1804,21 +1804,16 @@ static void rtl8139_tx_timeout (struct net_device *dev)
" (queue head)" : "");
tp->xstats.tx_timeouts++;
/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
printk(KERN_DEBUG "%s: tx_timeout\n", dev->name);
if (EtherCAT_dev_is_ec(rtl_ec_dev, dev))
{
EtherCAT_dev_state(rtl_ec_dev, EC_DEVICE_STATE_TIMEOUT);
}
printk(KERN_DEBUG "%s: tx_timeout\n", dev->name);
/* disable Tx ASAP, if not already */
tmp8 = RTL_R8 (ChipCmd);
if (tmp8 & CmdTxEnb)
RTL_W8 (ChipCmd, CmdRxEnb);
/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
if (!EtherCAT_dev_is_ec(rtl_ec_dev, dev))
{
spin_lock(&tp->rx_lock);
@@ -1840,7 +1835,7 @@ static void rtl8139_tx_timeout (struct net_device *dev)
}
spin_unlock(&tp->rx_lock);
}
}
else
{
rtl8139_tx_clear (tp);
@@ -1951,14 +1946,6 @@ static void rtl8139_tx_interrupt (struct net_device *dev,
tp->stats.tx_carrier_errors++;
if (txstatus & TxOutOfWindow)
tp->stats.tx_window_errors++;
/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
if (EtherCAT_dev_is_ec(rtl_ec_dev, dev))
EtherCAT_dev_state(rtl_ec_dev, EC_DEVICE_STATE_ERROR);
/* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
} else {
if (txstatus & TxUnderrun) {
/* Add 64 to the Tx FIFO threshold. */
@@ -2033,15 +2020,6 @@ static void rtl8139_rx_err (u32 rx_status, struct net_device *dev,
tp->xstats.rx_lost_in_ring++;
}
/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
if (EtherCAT_dev_is_ec(rtl_ec_dev, dev))
{
EtherCAT_dev_state(rtl_ec_dev, EC_DEVICE_STATE_ERROR);
}
/* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
#ifndef CONFIG_8139_OLD_RX_RESET
tmp8 = RTL_R8 (ChipCmd);
RTL_W8 (ChipCmd, tmp8 & ~CmdRxEnb);

View File

@@ -14,23 +14,10 @@
/*****************************************************************************/
struct ec_device;
typedef struct ec_device ec_device_t;
/*****************************************************************************/
typedef enum
{
EC_DEVICE_STATE_READY = 0,
EC_DEVICE_STATE_SENT,
EC_DEVICE_STATE_RECEIVED,
EC_DEVICE_STATE_TIMEOUT,
EC_DEVICE_STATE_ERROR
}
ec_device_state_t;
/*****************************************************************************/
ec_device_t *EtherCAT_dev_register(unsigned int, struct net_device *,
irqreturn_t (*)(int, void *,
struct pt_regs *),
@@ -38,7 +25,6 @@ ec_device_t *EtherCAT_dev_register(unsigned int, struct net_device *,
void EtherCAT_dev_unregister(unsigned int, ec_device_t *);
int EtherCAT_dev_is_ec(const ec_device_t *, const struct net_device *);
void EtherCAT_dev_state(ec_device_t *, ec_device_state_t);
void EtherCAT_dev_receive(ec_device_t *, const void *, size_t);
void EtherCAT_dev_link_state(ec_device_t *, uint8_t);

View File

@@ -63,9 +63,10 @@ ec_domain_t *EtherCAT_rt_master_register_domain(ec_master_t *master,
unsigned int timeout_us);
int EtherCAT_rt_master_activate(ec_master_t *master);
int EtherCAT_rt_master_deactivate(ec_master_t *master);
void EtherCAT_rt_master_xio(ec_master_t *master);
void EtherCAT_rt_master_debug(ec_master_t *master, int level);
void EtherCAT_rt_master_print(const ec_master_t *master);
@@ -81,7 +82,11 @@ ec_slave_t *EtherCAT_rt_register_slave_field(ec_domain_t *domain,
unsigned int field_index,
unsigned int field_count);
int EtherCAT_rt_domain_xio(ec_domain_t *domain);
int EtherCAT_rt_register_domain_fields(ec_domain_t *domain,
ec_field_init_t *fields);
void EtherCAT_rt_domain_queue(ec_domain_t *domain);
void EtherCAT_rt_domain_process(ec_domain_t *domain);
/*****************************************************************************/
// Slave Methods

View File

@@ -15,13 +15,10 @@ ifneq ($(KERNELRELEASE),)
obj-m := ec_master.o
ec_master-objs := module.o master.o device.o slave.o frame.o types.o \
ec_master-objs := module.o master.o device.o slave.o command.o types.o \
domain.o canopen.o
REV = `svnversion $(src)`
DATE = `date`
EXTRA_CFLAGS = -DEC_REV="$(REV)" -DEC_USER="$(USER)" -DEC_DATE="$(DATE)"
EXTRA_CFLAGS := -DSVNREV=$(shell svnversion $(src)) -DUSER=$(USER)
#------------------------------------------------------------------------------
@@ -48,7 +45,7 @@ doc:
cleandoc:
@rm -rf doc
.PHONY: doc
.PHONY: doc cleandoc modules clean
#------------------------------------------------------------------------------

View File

@@ -28,10 +28,11 @@ int EtherCAT_rt_canopen_sdo_write(ec_slave_t *slave, /**< EtherCAT-Slave */
size_t size /**< Größe des Datenfeldes */
)
{
unsigned char data[0xF6];
ec_frame_t frame;
unsigned int tries_left, i;
uint8_t data[0xF6];
ec_command_t command;
unsigned int i;
ec_master_t *master;
cycles_t start, end, timeout;
memset(data, 0x00, 0xF6);
@@ -56,53 +57,48 @@ int EtherCAT_rt_canopen_sdo_write(ec_slave_t *slave, /**< EtherCAT-Slave */
value >>= 8;
}
ec_frame_init_npwr(&frame, master, slave->station_address,
0x1800, 0xF6, data);
if (unlikely(ec_frame_send_receive(&frame))) {
ec_command_init_npwr(&command, slave->station_address, 0x1800, 0xF6, data);
if (unlikely(ec_master_simple_io(master, &command))) {
EC_ERR("Mailbox sending failed on slave %i!\n", slave->ring_position);
return -1;
}
// Read "written bit" of Sync-Manager
start = get_cycles();
timeout = cpu_khz; // 1ms
tries_left = 10;
while (tries_left)
do
{
ec_frame_init_nprd(&frame, master, slave->station_address, 0x808, 8);
if (unlikely(ec_frame_send_receive(&frame) < 0)) {
ec_command_init_nprd(&command, slave->station_address, 0x808, 8);
if (unlikely(ec_master_simple_io(master, &command))) {
EC_ERR("Mailbox checking failed on slave %i!\n",
slave->ring_position);
return -1;
}
if (EC_READ_U8(frame.data + 5) & 8) { // Written bit is high
break;
}
end = get_cycles();
udelay(1000);
tries_left--;
if (EC_READ_U8(command.data + 5) & 8) break; // Written bit is high
}
while ((end - start) < timeout);
if (!tries_left) {
if ((end - start) >= timeout) {
EC_ERR("Mailbox check - Slave %i timed out.\n", slave->ring_position);
return -1;
}
ec_frame_init_nprd(&frame, master, slave->station_address, 0x18F6, 0xF6);
if (unlikely(ec_frame_send_receive(&frame) < 0)) {
ec_command_init_nprd(&command, slave->station_address, 0x18F6, 0xF6);
if (unlikely(ec_master_simple_io(master, &command))) {
EC_ERR("Mailbox receiving failed on slave %i!\n",
slave->ring_position);
return -1;
}
if (EC_READ_U8 (frame.data + 5) != 0x03 || // COE
EC_READ_U16(frame.data + 6) != 0x3000 || // SDO response
EC_READ_U8 (frame.data + 8) >> 5 != 0x03 || // Download response
EC_READ_U16(frame.data + 9) != sdo_index || // Index
EC_READ_U8 (frame.data + 11) != sdo_subindex) // Subindex
if (EC_READ_U8 (command.data + 5) != 0x03 || // COE
EC_READ_U16(command.data + 6) != 0x3000 || // SDO response
EC_READ_U8 (command.data + 8) >> 5 != 0x03 || // Download response
EC_READ_U16(command.data + 9) != sdo_index || // Index
EC_READ_U8 (command.data + 11) != sdo_subindex) // Subindex
{
EC_ERR("Illegal mailbox response at slave %i!\n",
slave->ring_position);
@@ -125,12 +121,11 @@ int EtherCAT_rt_canopen_sdo_read(ec_slave_t *slave, /**< EtherCAT-Slave */
)
{
unsigned char data[0xF6];
ec_frame_t frame;
unsigned int tries_left;
ec_command_t command;
ec_master_t *master;
cycles_t start, end, timeout;
memset(data, 0x00, 0xF6);
master = slave->master;
EC_WRITE_U16(data, 0x0006); // Length of the Mailbox service data
@@ -142,60 +137,58 @@ int EtherCAT_rt_canopen_sdo_read(ec_slave_t *slave, /**< EtherCAT-Slave */
EC_WRITE_U16(data + 9, sdo_index);
EC_WRITE_U8 (data + 11, sdo_subindex);
ec_frame_init_npwr(&frame, master, slave->station_address,
0x1800, 0xF6, data);
if (unlikely(ec_frame_send_receive(&frame) < 0)) {
ec_command_init_npwr(&command, slave->station_address, 0x1800, 0xF6, data);
if (unlikely(ec_master_simple_io(master, &command))) {
EC_ERR("Mailbox sending failed on slave %i!\n", slave->ring_position);
return -1;
}
// Read "written bit" of Sync-Manager
tries_left = 10;
while (tries_left)
{
ec_frame_init_nprd(&frame, master, slave->station_address, 0x808, 8);
start = get_cycles();
timeout = cpu_khz; // 1ms
if (unlikely(ec_frame_send_receive(&frame) < 0)) {
do
{
ec_command_init_nprd(&command, slave->station_address, 0x808, 8);
if (unlikely(ec_master_simple_io(master, &command))) {
EC_ERR("Mailbox checking failed on slave %i!\n",
slave->ring_position);
return -1;
}
if (EC_READ_U8(frame.data + 5) & 8) { // Written bit is high
end = get_cycles();
if (EC_READ_U8(command.data + 5) & 8) { // Written bit is high
break;
}
udelay(1000);
tries_left--;
}
while (likely((end - start) < timeout));
if (!tries_left) {
if (unlikely((end - start) >= timeout)) {
EC_ERR("Mailbox check - Slave %i timed out.\n", slave->ring_position);
return -1;
}
ec_frame_init_nprd(&frame, master, slave->station_address, 0x18F6, 0xF6);
if (unlikely(ec_frame_send_receive(&frame) < 0)) {
ec_command_init_nprd(&command, slave->station_address, 0x18F6, 0xF6);
if (unlikely(ec_master_simple_io(master, &command))) {
EC_ERR("Mailbox receiving failed on slave %i!\n",
slave->ring_position);
return -1;
}
if (EC_READ_U8 (frame.data + 5) != 0x03 || // COE
EC_READ_U16(frame.data + 6) != 0x3000 || // SDO response
EC_READ_U8 (frame.data + 8) >> 5 != 0x02 || // Upload response
EC_READ_U16(frame.data + 9) != sdo_index || // Index
EC_READ_U8 (frame.data + 11) != sdo_subindex) // Subindex
if (EC_READ_U8 (command.data + 5) != 0x03 || // COE
EC_READ_U16(command.data + 6) != 0x3000 || // SDO response
EC_READ_U8 (command.data + 8) >> 5 != 0x02 || // Upload response
EC_READ_U16(command.data + 9) != sdo_index || // Index
EC_READ_U8 (command.data + 11) != sdo_subindex) // Subindex
{
EC_ERR("Illegal mailbox response at slave %i!\n",
slave->ring_position);
return -1;
}
*value = EC_READ_U32(frame.data + 12);
*value = EC_READ_U32(command.data + 12);
return 0;
}
@@ -213,7 +206,8 @@ int EtherCAT_rt_canopen_sdo_read(ec_slave_t *slave, /**< EtherCAT-Slave */
int EtherCAT_rt_canopen_sdo_addr_write(ec_master_t *master,
/**< EtherCAT-Master */
const char *addr,
/**< Addresse, siehe ec_address() */
/**< Addresse, siehe
ec_master_slave_address() */
uint16_t index,
/**< SDO-Index */
uint8_t subindex,
@@ -225,7 +219,7 @@ int EtherCAT_rt_canopen_sdo_addr_write(ec_master_t *master,
)
{
ec_slave_t *slave;
if (!(slave = ec_address(master, addr))) return -1;
if (!(slave = ec_master_slave_address(master, addr))) return -1;
return EtherCAT_rt_canopen_sdo_write(slave, index, subindex, value, size);
}
@@ -242,7 +236,8 @@ int EtherCAT_rt_canopen_sdo_addr_write(ec_master_t *master,
int EtherCAT_rt_canopen_sdo_addr_read(ec_master_t *master,
/**< EtherCAT-Slave */
const char *addr,
/**< Addresse, siehe ec_address() */
/**< Addresse, siehe
ec_master_slave_address() */
uint16_t index,
/**< SDO-Index */
uint8_t subindex,
@@ -252,7 +247,7 @@ int EtherCAT_rt_canopen_sdo_addr_read(ec_master_t *master,
)
{
ec_slave_t *slave;
if (!(slave = ec_address(master, addr))) return -1;
if (!(slave = ec_master_slave_address(master, addr))) return -1;
return EtherCAT_rt_canopen_sdo_read(slave, index, subindex, value);
}

235
master/command.c Normal file
View File

@@ -0,0 +1,235 @@
/******************************************************************************
*
* c o m m a n d . c
*
* Methoden für ein EtherCAT-Kommando.
*
* $Id$
*
*****************************************************************************/
#include <linux/slab.h>
#include <linux/delay.h>
#include "../include/EtherCAT_si.h"
#include "command.h"
#include "master.h"
/*****************************************************************************/
#define EC_FUNC_HEADER \
command->index = 0; \
command->working_counter = 0; \
command->state = EC_CMD_INIT;
#define EC_FUNC_WRITE_FOOTER \
command->data_size = data_size; \
memcpy(command->data, data, data_size);
#define EC_FUNC_READ_FOOTER \
command->data_size = data_size; \
memset(command->data, 0x00, data_size);
/*****************************************************************************/
/**
Initialisiert ein EtherCAT-NPRD-Kommando.
Node-adressed physical read.
*/
void ec_command_init_nprd(ec_command_t *command,
/**< EtherCAT-Rahmen */
uint16_t node_address,
/**< Adresse des Knotens (Slaves) */
uint16_t offset,
/**< Physikalische Speicheradresse im Slave */
size_t data_size
/**< Länge der zu lesenden Daten */
)
{
if (unlikely(node_address == 0x0000))
EC_WARN("Using node address 0x0000!\n");
EC_FUNC_HEADER;
command->type = EC_CMD_NPRD;
command->address.physical.slave = node_address;
command->address.physical.mem = offset;
EC_FUNC_READ_FOOTER;
}
/*****************************************************************************/
/**
Initialisiert ein EtherCAT-NPWR-Kommando.
Node-adressed physical write.
*/
void ec_command_init_npwr(ec_command_t *command,
/**< EtherCAT-Rahmen */
uint16_t node_address,
/**< Adresse des Knotens (Slaves) */
uint16_t offset,
/**< Physikalische Speicheradresse im Slave */
size_t data_size,
/**< Länge der zu schreibenden Daten */
const uint8_t *data
/**< Zeiger auf Speicher mit zu schreibenden Daten */
)
{
if (unlikely(node_address == 0x0000))
EC_WARN("Using node address 0x0000!\n");
EC_FUNC_HEADER;
command->type = EC_CMD_NPWR;
command->address.physical.slave = node_address;
command->address.physical.mem = offset;
EC_FUNC_WRITE_FOOTER;
}
/*****************************************************************************/
/**
Initialisiert ein EtherCAT-APRD-Kommando.
Autoincrement physical read.
*/
void ec_command_init_aprd(ec_command_t *command,
/**< EtherCAT-Rahmen */
uint16_t ring_position,
/**< Position des Slaves im Bus */
uint16_t offset,
/**< Physikalische Speicheradresse im Slave */
size_t data_size
/**< Länge der zu lesenden Daten */
)
{
EC_FUNC_HEADER;
command->type = EC_CMD_APRD;
command->address.physical.slave = (int16_t) ring_position * (-1);
command->address.physical.mem = offset;
EC_FUNC_READ_FOOTER;
}
/*****************************************************************************/
/**
Initialisiert ein EtherCAT-APWR-Kommando.
Autoincrement physical write.
*/
void ec_command_init_apwr(ec_command_t *command,
/**< EtherCAT-Rahmen */
uint16_t ring_position,
/**< Position des Slaves im Bus */
uint16_t offset,
/**< Physikalische Speicheradresse im Slave */
size_t data_size,
/**< Länge der zu schreibenden Daten */
const uint8_t *data
/**< Zeiger auf Speicher mit zu schreibenden Daten */
)
{
EC_FUNC_HEADER;
command->type = EC_CMD_APWR;
command->address.physical.slave = (int16_t) ring_position * (-1);
command->address.physical.mem = offset;
EC_FUNC_WRITE_FOOTER;
}
/*****************************************************************************/
/**
Initialisiert ein EtherCAT-BRD-Kommando.
Broadcast read.
*/
void ec_command_init_brd(ec_command_t *command,
/**< EtherCAT-Rahmen */
uint16_t offset,
/**< Physikalische Speicheradresse im Slave */
size_t data_size
/**< Länge der zu lesenden Daten */
)
{
EC_FUNC_HEADER;
command->type = EC_CMD_BRD;
command->address.physical.slave = 0x0000;
command->address.physical.mem = offset;
EC_FUNC_READ_FOOTER;
}
/*****************************************************************************/
/**
Initialisiert ein EtherCAT-BWR-Kommando.
Broadcast write.
*/
void ec_command_init_bwr(ec_command_t *command,
/**< EtherCAT-Rahmen */
uint16_t offset,
/**< Physikalische Speicheradresse im Slave */
size_t data_size,
/**< Länge der zu schreibenden Daten */
const uint8_t *data
/**< Zeiger auf Speicher mit zu schreibenden Daten */
)
{
EC_FUNC_HEADER;
command->type = EC_CMD_BWR;
command->address.physical.slave = 0x0000;
command->address.physical.mem = offset;
EC_FUNC_WRITE_FOOTER;
}
/*****************************************************************************/
/**
Initialisiert ein EtherCAT-LRW-Kommando.
Logical read write.
*/
void ec_command_init_lrw(ec_command_t *command,
/**< EtherCAT-Rahmen */
uint32_t offset,
/**< Logische Startadresse */
size_t data_size,
/**< Länge der zu lesenden/schreibenden Daten */
uint8_t *data
/**< Zeiger auf die Daten */
)
{
EC_FUNC_HEADER;
command->type = EC_CMD_LRW;
command->address.logical = offset;
EC_FUNC_WRITE_FOOTER;
}
/*****************************************************************************/
/* Emacs-Konfiguration
;;; Local Variables: ***
;;; c-basic-offset:4 ***
;;; End: ***
*/

118
master/command.h Normal file
View File

@@ -0,0 +1,118 @@
/******************************************************************************
*
* c o m m a n d . h
*
* Struktur für ein EtherCAT-Kommando.
*
* $Id$
*
*****************************************************************************/
#ifndef _EC_COMMAND_H_
#define _EC_COMMAND_H_
#include <linux/list.h>
#include "globals.h"
/*****************************************************************************/
/**
EtherCAT-Kommando-Typ.
*/
typedef enum
{
EC_CMD_NONE = 0x00, /**< Dummy */
EC_CMD_APRD = 0x01, /**< Auto-increment physical read */
EC_CMD_APWR = 0x02, /**< Auto-increment physical write */
EC_CMD_NPRD = 0x04, /**< Node-addressed physical read */
EC_CMD_NPWR = 0x05, /**< Node-addressed physical write */
EC_CMD_BRD = 0x07, /**< Broadcast read */
EC_CMD_BWR = 0x08, /**< Broadcast write */
EC_CMD_LRW = 0x0C /**< Logical read/write */
}
ec_command_type_t;
/**
EtherCAT-Kommando-Zustand.
*/
typedef enum
{
EC_CMD_INIT, /**< Neues Kommando */
EC_CMD_QUEUED, /**< Kommando in Warteschlange */
EC_CMD_SENT, /**< Kommando gesendet */
EC_CMD_RECEIVED, /**< Kommando empfangen */
EC_CMD_TIMEOUT, /**< Zeitgrenze überschritten */
EC_CMD_ERROR /**< Fehler beim Senden oder Empfangen */
}
ec_command_state_t;
/*****************************************************************************/
/**
EtherCAT-Adresse.
Im EtherCAT-Kommando sind 4 Bytes für die Adresse reserviert, die je nach
Kommandotyp, eine andere Bedeutung haben können: Bei Autoinkrementbefehlen
sind die ersten zwei Bytes die (negative) Autoinkrement-Adresse, bei Knoten-
adressierten Befehlen entsprechen sie der Knotenadresse. Das dritte und
vierte Byte entspricht in diesen Fällen der physikalischen Speicheradresse
auf dem Slave. Bei einer logischen Adressierung entsprechen alle vier Bytes
der logischen Adresse.
*/
typedef union
{
struct
{
uint16_t slave; /**< Adresse des Slaves (Ringposition oder Knoten) */
uint16_t mem; /**< Physikalische Speicheradresse im Slave */
}
physical; /**< Physikalische Adresse */
uint32_t logical; /**< Logische Adresse */
}
ec_address_t;
/*****************************************************************************/
/**
EtherCAT-Kommando.
*/
typedef struct
{
struct list_head list; /**< Nötig für Liste */
ec_command_type_t type; /**< Typ des Kommandos (APRD, NPWR, etc) */
ec_address_t address; /**< Adresse des/der Empfänger */
uint8_t data[EC_MAX_DATA_SIZE]; /**< Kommandodaten */
size_t data_size; /**< Länge der zu sendenden und/oder empfangenen Daten */
uint8_t index; /**< Kommando-Index, wird vom Master beim Senden gesetzt. */
uint16_t working_counter; /**< Working-Counter */
ec_command_state_t state; /**< Zustand */
}
ec_command_t;
/*****************************************************************************/
void ec_command_init_nprd(ec_command_t *, uint16_t, uint16_t, size_t);
void ec_command_init_npwr(ec_command_t *, uint16_t, uint16_t, size_t,
const uint8_t *);
void ec_command_init_aprd(ec_command_t *, uint16_t, uint16_t, size_t);
void ec_command_init_apwr(ec_command_t *, uint16_t, uint16_t, size_t,
const uint8_t *);
void ec_command_init_brd(ec_command_t *, uint16_t, size_t);
void ec_command_init_bwr(ec_command_t *, uint16_t, size_t, const uint8_t *);
void ec_command_init_lrw(ec_command_t *, uint32_t, size_t, uint8_t *);
/*****************************************************************************/
#endif
/* Emacs-Konfiguration
;;; Local Variables: ***
;;; c-basic-offset:4 ***
;;; End: ***
*/

View File

@@ -19,6 +19,11 @@
/*****************************************************************************/
void ec_data_print(const uint8_t *, size_t);
void ec_data_print_diff(const uint8_t *, const uint8_t *, size_t);
/*****************************************************************************/
/**
EtherCAT-Geräte-Konstuktor.
@@ -26,26 +31,36 @@
*/
int ec_device_init(ec_device_t *device, /**< EtherCAT-Gerät */
ec_master_t *master /**< Zugehöriger Master */
ec_master_t *master, /**< Zugehöriger Master */
struct net_device *net_dev, /**< Net-Device */
ec_isr_t isr, /**< Adresse der ISR */
struct module *module /**< Modul-Adresse */
)
{
struct ethhdr *eth;
device->master = master;
device->dev = NULL;
device->dev = net_dev;
device->isr = isr;
device->module = module;
device->open = 0;
device->tx_time = 0;
device->rx_time = 0;
device->state = EC_DEVICE_STATE_READY;
device->rx_data_size = 0;
device->isr = NULL;
device->module = NULL;
device->error_reported = 0;
device->link_state = 0; // down
if ((device->tx_skb = dev_alloc_skb(ETH_HLEN + EC_MAX_FRAME_SIZE)) == NULL) {
if (!(device->tx_skb = dev_alloc_skb(ETH_HLEN + EC_MAX_FRAME_SIZE))) {
EC_ERR("Error allocating device socket buffer!\n");
return -1;
}
device->tx_skb->dev = net_dev;
// Ethernet-II-Header hinzufuegen
skb_reserve(device->tx_skb, ETH_HLEN);
eth = (struct ethhdr *) skb_push(device->tx_skb, ETH_HLEN);
eth->h_proto = htons(0x88A4);
memcpy(eth->h_source, net_dev->dev_addr, net_dev->addr_len);
memset(eth->h_dest, 0xFF, net_dev->addr_len);
return 0;
}
@@ -61,13 +76,7 @@ int ec_device_init(ec_device_t *device, /**< EtherCAT-Ger
void ec_device_clear(ec_device_t *device /**< EtherCAT-Gerät */)
{
if (device->open) ec_device_close(device);
device->dev = NULL;
if (device->tx_skb) {
dev_kfree_skb(device->tx_skb);
device->tx_skb = NULL;
}
if (device->tx_skb) dev_kfree_skb(device->tx_skb);
}
/*****************************************************************************/
@@ -100,8 +109,6 @@ int ec_device_open(ec_device_t *device /**< EtherCAT-Ger
// Device could have received frames before
for (i = 0; i < 4; i++) ec_device_call_isr(device);
// Reset old device state
device->state = EC_DEVICE_STATE_READY;
device->link_state = 0;
if (device->dev->open(device->dev) == 0) device->open = 1;
@@ -127,10 +134,10 @@ int ec_device_close(ec_device_t *device /**< EtherCAT-Ger
if (!device->open) {
EC_WARN("Device already closed!\n");
return 0;
}
else {
if (device->dev->stop(device->dev) == 0) device->open = 0;
}
if (device->dev->stop(device->dev) == 0) device->open = 0;
return !device->open ? 0 : -1;
}
@@ -138,18 +145,14 @@ int ec_device_close(ec_device_t *device /**< EtherCAT-Ger
/*****************************************************************************/
/**
Bereitet den geräteinternen Socket-Buffer auf den Versand vor.
Liefert einen Zeiger auf den Sende-Speicher.
\return Zeiger auf den Speicher, in den die Frame-Daten sollen.
*/
uint8_t *ec_device_prepare(ec_device_t *device /**< EtherCAT-Gerät */)
uint8_t *ec_device_tx_data(ec_device_t *device /**< EtherCAT-Gerät */)
{
skb_trim(device->tx_skb, 0); // Auf Länge 0 abschneiden
skb_reserve(device->tx_skb, ETH_HLEN); // Reserve für Ethernet-II-Header
// Vorerst Speicher für maximal langen Frame reservieren
return skb_put(device->tx_skb, EC_MAX_FRAME_SIZE);
return device->tx_skb->data + ETH_HLEN;
}
/*****************************************************************************/
@@ -163,64 +166,26 @@ uint8_t *ec_device_prepare(ec_device_t *device /**< EtherCAT-Ger
*/
void ec_device_send(ec_device_t *device, /**< EtherCAT-Gerät */
unsigned int length /**< Länge der zu sendenden Daten */
size_t size /**< Größe der zu sendenden Daten */
)
{
struct ethhdr *eth;
if (unlikely(!device->link_state)) // Link down
return;
// Framegröße auf (jetzt bekannte) Länge abschneiden
skb_trim(device->tx_skb, length);
// Ethernet-II-Header hinzufuegen
eth = (struct ethhdr *) skb_push(device->tx_skb, ETH_HLEN);
eth->h_proto = htons(0x88A4);
memcpy(eth->h_source, device->dev->dev_addr, device->dev->addr_len);
memset(eth->h_dest, 0xFF, device->dev->addr_len);
device->state = EC_DEVICE_STATE_SENT;
device->rx_data_size = 0;
device->tx_skb->len = ETH_HLEN + size;
if (unlikely(device->master->debug_level > 1)) {
EC_DBG("Sending frame:\n");
ec_data_print(device->tx_skb->data + ETH_HLEN, device->tx_skb->len);
EC_DBG("sending frame:\n");
ec_data_print(device->tx_skb->data + ETH_HLEN, size);
}
// Senden einleiten
rdtscl(device->tx_time); // Get CPU cycles
device->dev->hard_start_xmit(device->tx_skb, device->dev);
}
/*****************************************************************************/
/**
Gibt die Anzahl der empfangenen Bytes zurück.
\return Empfangene Bytes, oder 0, wenn kein Frame empfangen wurde.
*/
unsigned int ec_device_received(const ec_device_t *device)
{
return device->rx_data_size;
}
/*****************************************************************************/
/**
Gibt die empfangenen Daten zurück.
\return Zeiger auf empfangene Daten.
*/
uint8_t *ec_device_data(ec_device_t *device)
{
return device->rx_data;
}
/*****************************************************************************/
/**
Ruft die Interrupt-Routine der Netzwerkkarte auf.
*/
@@ -232,49 +197,6 @@ void ec_device_call_isr(ec_device_t *device /**< EtherCAT-Ger
/*****************************************************************************/
/**
Gibt alle Informationen über das Device-Objekt aus.
*/
void ec_device_print(ec_device_t *device /**< EtherCAT-Gerät */)
{
EC_DBG("---EtherCAT device information begin---\n");
if (device) {
EC_DBG("Assigned net_device: %X\n", (u32) device->dev);
EC_DBG("Transmit socket buffer: %X\n", (u32) device->tx_skb);
EC_DBG("Time of last transmission: %u\n", (u32) device->tx_time);
EC_DBG("Time of last receive: %u\n", (u32) device->rx_time);
EC_DBG("Actual device state: %i\n", (u8) device->state);
EC_DBG("Receive buffer: %X\n", (u32) device->rx_data);
EC_DBG("Receive buffer fill state: %u/%u\n",
(u32) device->rx_data_size, EC_MAX_FRAME_SIZE);
}
else {
EC_DBG("Device is NULL!\n");
}
EC_DBG("---EtherCAT device information end---\n");
}
/*****************************************************************************/
/**
Gibt das letzte Rahmenpaar aus.
*/
void ec_device_debug(const ec_device_t *device /**< EtherCAT-Gerät */)
{
EC_DBG(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
ec_data_print(device->tx_skb->data + ETH_HLEN, device->tx_skb->len);
EC_DBG("--------------------------------------\n");
ec_data_print_diff(device->tx_skb->data + ETH_HLEN, device->rx_data,
device->rx_data_size);
EC_DBG("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
}
/*****************************************************************************/
/**
Gibt Frame-Inhalte zwecks Debugging aus.
*/
@@ -327,19 +249,6 @@ void ec_data_print_diff(const uint8_t *d1, /**< Daten 1 */
*
*****************************************************************************/
/**
Setzt den Zustand des EtherCAT-Gerätes.
*/
void EtherCAT_dev_state(ec_device_t *device, /**< EtherCAT-Gerät */
ec_device_state_t state /**< Neuer Zustand */
)
{
device->state = state;
}
/*****************************************************************************/
/**
Prüft, ob das Net-Device \a dev zum registrierten EtherCAT-Gerät gehört.
@@ -366,16 +275,12 @@ void EtherCAT_dev_receive(ec_device_t *device, /**< EtherCAT-Ger
size_t size /**< Größe der empfangenen Daten */
)
{
// Copy received data to ethercat-device buffer
memcpy(device->rx_data, data, size);
device->rx_data_size = size;
device->state = EC_DEVICE_STATE_RECEIVED;
if (unlikely(device->master->debug_level > 1)) {
EC_DBG("Received frame:\n");
ec_data_print_diff(device->tx_skb->data + ETH_HLEN, device->rx_data,
device->rx_data_size);
ec_data_print_diff(device->tx_skb->data + ETH_HLEN, data, size);
}
ec_master_receive(device->master, data, size);
}
/*****************************************************************************/
@@ -397,7 +302,6 @@ void EtherCAT_dev_link_state(ec_device_t *device, /**< EtherCAT-Ger
/*****************************************************************************/
EXPORT_SYMBOL(EtherCAT_dev_is_ec);
EXPORT_SYMBOL(EtherCAT_dev_state);
EXPORT_SYMBOL(EtherCAT_dev_receive);
EXPORT_SYMBOL(EtherCAT_dev_link_state);

View File

@@ -17,6 +17,8 @@
#include "../include/EtherCAT_dev.h"
#include "globals.h"
typedef irqreturn_t (*ec_isr_t)(int, void *, struct pt_regs *);
/*****************************************************************************/
/**
@@ -33,36 +35,24 @@ struct ec_device
struct net_device *dev; /**< Zeiger auf das reservierte net_device */
uint8_t open; /**< Das net_device ist geoeffnet. */
struct sk_buff *tx_skb; /**< Zeiger auf Transmit-Socketbuffer */
unsigned long tx_time; /**< Zeit des letzten Sendens */
unsigned long rx_time; /**< Zeit des letzten Empfangs */
ec_device_state_t state; /**< Zustand des Gerätes */
uint8_t rx_data[EC_MAX_FRAME_SIZE]; /**< Speicher für empfangene Rahmen */
size_t rx_data_size; /**< Länge des empfangenen Rahmens */
irqreturn_t (*isr)(int, void *, struct pt_regs *); /**< Adresse der ISR */
ec_isr_t isr; /**< Adresse der ISR */
struct module *module; /**< Zeiger auf das Modul, das das Gerät zur
Verfügung stellt. */
uint8_t error_reported; /**< Zeigt an, ob ein Fehler im zyklischen Code
bereits gemeldet wurde. */
uint8_t link_state; /**< Verbindungszustand */
};
/*****************************************************************************/
int ec_device_init(ec_device_t *, ec_master_t *);
int ec_device_init(ec_device_t *, ec_master_t *, struct net_device *,
ec_isr_t, struct module *);
void ec_device_clear(ec_device_t *);
int ec_device_open(ec_device_t *);
int ec_device_close(ec_device_t *);
void ec_device_call_isr(ec_device_t *);
uint8_t *ec_device_prepare(ec_device_t *);
uint8_t *ec_device_tx_data(ec_device_t *);
void ec_device_send(ec_device_t *, size_t);
unsigned int ec_device_received(const ec_device_t *);
uint8_t *ec_device_data(ec_device_t *);
void ec_device_debug(const ec_device_t *);
void ec_data_print(const uint8_t *, size_t);
void ec_data_print_diff(const uint8_t *, const uint8_t *, size_t);
/*****************************************************************************/

View File

@@ -12,6 +12,8 @@
#include "domain.h"
#include "master.h"
void ec_domain_clear_field_regs(ec_domain_t *);
/*****************************************************************************/
/**
@@ -30,6 +32,8 @@ void ec_domain_init(ec_domain_t *domain, /**< Dom
domain->data = NULL;
domain->data_size = 0;
domain->commands = NULL;
domain->command_count = 0;
domain->base_address = 0;
domain->response_count = 0xFFFFFFFF;
@@ -44,17 +48,10 @@ void ec_domain_init(ec_domain_t *domain, /**< Dom
void ec_domain_clear(ec_domain_t *domain /**< Domäne */)
{
ec_field_reg_t *field_reg, *next;
if (domain->data) kfree(domain->data);
if (domain->commands) kfree(domain->commands);
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);
}
ec_domain_clear_field_regs(domain);
}
/*****************************************************************************/
@@ -98,6 +95,22 @@ int ec_domain_reg_field(ec_domain_t *domain, /**< Dom
/*****************************************************************************/
/**
Gibt die Liste der registrierten Datenfelder frei.
*/
void ec_domain_clear_field_regs(ec_domain_t *domain)
{
ec_field_reg_t *field_reg, *next;
list_for_each_entry_safe(field_reg, next, &domain->field_regs, list) {
list_del(&field_reg->list);
kfree(field_reg);
}
}
/*****************************************************************************/
/**
Erzeugt eine Domäne.
@@ -111,7 +124,7 @@ int ec_domain_alloc(ec_domain_t *domain, /**< Dom
uint32_t base_address /**< Logische Basisadresse */
)
{
ec_field_reg_t *field_reg, *next;
ec_field_reg_t *field_reg;
ec_slave_t *slave;
ec_fmmu_t *fmmu;
unsigned int i, j, found, data_offset;
@@ -139,43 +152,52 @@ int ec_domain_alloc(ec_domain_t *domain, /**< Dom
if (!domain->data_size) {
EC_WARN("Domain 0x%08X contains no data!\n", (u32) domain);
ec_domain_clear_field_regs(domain);
return 0;
}
else {
// Prozessdaten allozieren
if (!(domain->data = kmalloc(domain->data_size, GFP_KERNEL))) {
EC_ERR("Failed to allocate domain data!\n");
// Prozessdaten allozieren
if (!(domain->data = kmalloc(domain->data_size, GFP_KERNEL))) {
EC_ERR("Failed to allocate domain data!\n");
return -1;
}
// Prozessdaten mit Nullen vorbelegen
memset(domain->data, 0x00, domain->data_size);
// Alle Prozessdatenzeiger setzen
list_for_each_entry(field_reg, &domain->field_regs, list) {
found = 0;
for (i = 0; i < field_reg->slave->fmmu_count; i++) {
fmmu = &field_reg->slave->fmmus[i];
if (fmmu->domain == domain && fmmu->sync == field_reg->sync) {
data_offset = fmmu->logical_start_address - base_address
+ field_reg->field_offset;
*field_reg->data_ptr = domain->data + data_offset;
found = 1;
break;
}
}
if (!found) { // Sollte nie passieren
EC_ERR("FMMU not found. Please report!\n");
return -1;
}
// Prozessdaten mit Nullen vorbelegen
memset(domain->data, 0x00, domain->data_size);
// Alle Prozessdatenzeiger setzen
list_for_each_entry(field_reg, &domain->field_regs, list) {
found = 0;
for (i = 0; i < field_reg->slave->fmmu_count; i++) {
fmmu = &field_reg->slave->fmmus[i];
if (fmmu->domain == domain && fmmu->sync == field_reg->sync) {
data_offset = fmmu->logical_start_address - base_address
+ field_reg->field_offset;
*field_reg->data_ptr = domain->data + data_offset;
found = 1;
break;
}
}
if (!found) { // Sollte nie passieren
EC_ERR("FMMU not found. Please report!\n");
return -1;
}
}
}
// Registrierungsliste wird jetzt nicht mehr gebraucht.
list_for_each_entry_safe(field_reg, next, &domain->field_regs, list) {
kfree(field_reg);
// Kommando-Array erzeugen
domain->command_count = domain->data_size / EC_MAX_DATA_SIZE + 1;
if (!(domain->commands = (ec_command_t *) kmalloc(sizeof(ec_command_t)
* domain->command_count,
GFP_KERNEL))) {
EC_ERR("Failed to allocate domain command array!\n");
return -1;
}
INIT_LIST_HEAD(&domain->field_regs); // wichtig!
EC_INFO("Domain %X - Allocated %i bytes in %i command(s)\n",
(u32) domain, domain->data_size, domain->command_count);
ec_domain_clear_field_regs(domain);
return 0;
}
@@ -192,8 +214,8 @@ void ec_domain_response_count(ec_domain_t *domain, /**< Dom
{
if (count != domain->response_count) {
domain->response_count = count;
EC_INFO("Domain %08X state change - %i slaves responding.\n",
(u32) domain, count);
EC_INFO("Domain %08X state change - %i slave%s responding.\n",
(u32) domain, count, count == 1 ? "" : "s");
}
}
@@ -209,17 +231,28 @@ void ec_domain_response_count(ec_domain_t *domain, /**< Dom
\return Zeiger auf den Slave bei Erfolg, sonst NULL
*/
ec_slave_t *EtherCAT_rt_register_slave_field(
ec_domain_t *domain, /**< Domäne */
const char *address, /**< ASCII-Addresse des Slaves, siehe ec_address() */
const char *vendor_name, /**< Herstellername */
const char *product_name, /**< Produktname */
void **data_ptr, /**< Adresse des Zeigers auf die Prozessdaten */
ec_field_type_t field_type, /**< Typ des Datenfeldes */
unsigned int field_index, /**< Gibt an, ab welchem Feld mit Typ
\a field_type gezählt werden soll. */
unsigned int field_count /**< Anzahl Felder des selben Typs */
)
ec_slave_t *EtherCAT_rt_register_slave_field(ec_domain_t *domain,
/**< Domäne */
const char *address,
/**< ASCII-Addresse des Slaves,
siehe ec_master_slave_address()
*/
const char *vendor_name,
/**< Herstellername */
const char *product_name,
/**< Produktname */
void **data_ptr,
/**< Adresse des Zeigers auf die
Prozessdaten */
ec_field_type_t field_type,
/**< Typ des Datenfeldes */
unsigned int field_index,
/**< Gibt an, ab welchem Feld mit
Typ \a field_type gezählt
werden soll. */
unsigned int field_count
/**< Anzahl Felder selben Typs */
)
{
ec_slave_t *slave;
const ec_slave_type_t *type;
@@ -237,7 +270,7 @@ ec_slave_t *EtherCAT_rt_register_slave_field(
master = domain->master;
// Adresse übersetzen
if ((slave = ec_address(master, address)) == NULL) return NULL;
if (!(slave = ec_master_slave_address(master, address))) return NULL;
if (!(type = slave->type)) {
EC_ERR("Slave \"%s\" (position %i) has unknown type!\n", address,
@@ -280,96 +313,96 @@ ec_slave_t *EtherCAT_rt_register_slave_field(
/*****************************************************************************/
/**
Sendet und empfängt Prozessdaten der angegebenen Domäne.
Registriert eine ganze Liste von Datenfeldern innerhalb einer Domäne.
Achtung: Die Liste muss mit einer NULL-Struktur ({}) abgeschlossen sein!
\return 0 bei Erfolg, sonst < 0
*/
int EtherCAT_rt_domain_xio(ec_domain_t *domain /**< Domäne */)
int EtherCAT_rt_register_domain_fields(ec_domain_t *domain,
/**< Domäne */
ec_field_init_t *fields
/**< Array mit Datenfeldern */
)
{
unsigned int offset, size, working_counter_sum;
unsigned long start_ticks, end_ticks, timeout_ticks;
ec_master_t *master;
ec_frame_t *frame;
ec_field_init_t *field;
master = domain->master;
frame = &domain->frame;
working_counter_sum = 0;
ec_cyclic_output(master);
if (unlikely(!master->device.link_state)) {
ec_domain_response_count(domain, working_counter_sum);
ec_device_call_isr(&master->device);
return -1;
}
rdtscl(start_ticks); // Sendezeit nehmen
timeout_ticks = domain->timeout_us * cpu_khz / 1000;
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)) {
master->device.state = EC_DEVICE_STATE_READY;
master->frames_lost++;
ec_cyclic_output(master);
ec_domain_response_count(domain, working_counter_sum);
for (field = fields; field->data; field++) {
if (!EtherCAT_rt_register_slave_field(domain, field->address,
field->vendor, field->product,
field->data, field->field_type,
field->field_index,
field->field_count)) {
return -1;
}
// Warten
do {
ec_device_call_isr(&master->device);
rdtscl(end_ticks); // Empfangszeit nehmen
}
while (unlikely(master->device.state == EC_DEVICE_STATE_SENT
&& end_ticks - start_ticks < timeout_ticks));
master->bus_time = (end_ticks - start_ticks) * 1000 / cpu_khz;
if (unlikely(end_ticks - start_ticks >= timeout_ticks)) {
if (master->device.state == EC_DEVICE_STATE_RECEIVED) {
master->frames_delayed++;
ec_cyclic_output(master);
}
else {
master->device.state = EC_DEVICE_STATE_READY;
master->frames_lost++;
ec_cyclic_output(master);
ec_domain_response_count(domain, working_counter_sum);
return -1;
}
}
if (unlikely(ec_frame_receive(frame) < 0)) {
ec_domain_response_count(domain, working_counter_sum);
return -1;
}
working_counter_sum += frame->working_counter;
// Daten vom Rahmen in den Prozessdatenspeicher kopieren
memcpy(domain->data + offset, frame->data, size);
offset += size;
}
ec_domain_response_count(domain, working_counter_sum);
return 0;
}
/*****************************************************************************/
/**
Setzt Prozessdaten-Kommandos in die Warteschlange des Masters.
*/
void EtherCAT_rt_domain_queue(ec_domain_t *domain /**< Domäne */)
{
unsigned int offset, i;
size_t size;
offset = 0;
for (i = 0; i < domain->command_count; i++) {
size = domain->data_size - offset;
if (size > EC_MAX_DATA_SIZE) size = EC_MAX_DATA_SIZE;
ec_command_init_lrw(domain->commands + i,
domain->base_address + offset, size,
domain->data + offset);
ec_master_queue_command(domain->master, domain->commands + i);
offset += size;
}
}
/*****************************************************************************/
/**
Verarbeitet empfangene Prozessdaten.
*/
void EtherCAT_rt_domain_process(ec_domain_t *domain /**< Domäne */)
{
unsigned int offset, working_counter_sum, i;
ec_command_t *command;
size_t size;
working_counter_sum = 0;
offset = 0;
for (i = 0; i < domain->command_count; i++) {
command = domain->commands + i;
size = domain->data_size - offset;
if (size > EC_MAX_DATA_SIZE) size = EC_MAX_DATA_SIZE;
if (command->state == EC_CMD_RECEIVED) {
// Daten vom Kommando- in den Prozessdatenspeicher kopieren
memcpy(domain->data + offset, command->data, size);
working_counter_sum += command->working_counter;
}
else if (unlikely(domain->master->debug_level)) {
EC_DBG("process data command not received!\n");
}
offset += size;
}
ec_domain_response_count(domain, working_counter_sum);
}
/*****************************************************************************/
EXPORT_SYMBOL(EtherCAT_rt_register_slave_field);
EXPORT_SYMBOL(EtherCAT_rt_domain_xio);
EXPORT_SYMBOL(EtherCAT_rt_register_domain_fields);
EXPORT_SYMBOL(EtherCAT_rt_domain_queue);
EXPORT_SYMBOL(EtherCAT_rt_domain_process);
/*****************************************************************************/

View File

@@ -15,7 +15,7 @@
#include "globals.h"
#include "slave.h"
#include "frame.h"
#include "command.h"
/*****************************************************************************/
@@ -46,17 +46,14 @@ struct ec_domain
{
struct list_head list; /**< Listenkopf */
ec_master_t *master; /**< EtherCAT-Master, zu der die Domäne gehört. */
unsigned char *data; /**< Prozessdaten */
unsigned int data_size; /**< Größe der Prozessdaten */
ec_frame_t frame; /**< EtherCAT-Frame für die Prozessdaten */
uint8_t *data; /**< Prozessdaten */
size_t data_size; /**< Größe der Prozessdaten */
ec_command_t *commands; /**< EtherCAT-Kommandos für die Prozessdaten */
unsigned int command_count; /**< Anzahl allozierter Kommandos */
ec_domain_mode_t mode;
unsigned int timeout_us; /**< Timeout in Mikrosekunden. */
unsigned int base_address; /**< Logische Basisaddresse der Domain */
unsigned int response_count; /**< Anzahl antwortender Slaves */
struct list_head field_regs; /**< Liste der Datenfeldregistrierungen */
};

View File

@@ -1,463 +0,0 @@
/******************************************************************************
*
* f r a m e . c
*
* Methoden für einen EtherCAT-Frame.
*
* $Id$
*
*****************************************************************************/
#include <linux/slab.h>
#include <linux/delay.h>
#include "../include/EtherCAT_si.h"
#include "frame.h"
#include "master.h"
/*****************************************************************************/
#define EC_FUNC_HEADER \
frame->master = master; \
frame->index = 0; \
frame->working_counter = 0;
#define EC_FUNC_WRITE_FOOTER \
frame->data_length = length; \
memcpy(frame->data, data, length);
#define EC_FUNC_READ_FOOTER \
frame->data_length = length; \
memset(frame->data, 0x00, length);
/*****************************************************************************/
/**
Initialisiert ein EtherCAT-NPRD-Kommando.
Node-adressed physical read.
*/
void ec_frame_init_nprd(ec_frame_t *frame,
/**< EtherCAT-Rahmen */
ec_master_t *master,
/**< EtherCAT-Master */
uint16_t node_address,
/**< Adresse des Knotens (Slaves) */
uint16_t offset,
/**< Physikalische Speicheradresse im Slave */
unsigned int length
/**< Länge der zu lesenden Daten */
)
{
if (unlikely(node_address == 0x0000))
EC_WARN("Using node address 0x0000!\n");
EC_FUNC_HEADER;
frame->type = ec_frame_type_nprd;
frame->address.physical.slave = node_address;
frame->address.physical.mem = offset;
EC_FUNC_READ_FOOTER;
}
/*****************************************************************************/
/**
Initialisiert ein EtherCAT-NPWR-Kommando.
Node-adressed physical write.
*/
void ec_frame_init_npwr(ec_frame_t *frame,
/**< EtherCAT-Rahmen */
ec_master_t *master,
/**< EtherCAT-Master */
uint16_t node_address,
/**< Adresse des Knotens (Slaves) */
uint16_t offset,
/**< Physikalische Speicheradresse im Slave */
unsigned int length,
/**< Länge der zu schreibenden Daten */
const uint8_t *data
/**< Zeiger auf Speicher mit zu schreibenden Daten */
)
{
if (unlikely(node_address == 0x0000))
EC_WARN("Using node address 0x0000!\n");
EC_FUNC_HEADER;
frame->type = ec_frame_type_npwr;
frame->address.physical.slave = node_address;
frame->address.physical.mem = offset;
EC_FUNC_WRITE_FOOTER;
}
/*****************************************************************************/
/**
Initialisiert ein EtherCAT-APRD-Kommando.
Autoincrement physical read.
*/
void ec_frame_init_aprd(ec_frame_t *frame,
/**< EtherCAT-Rahmen */
ec_master_t *master,
/**< EtherCAT-Master */
uint16_t ring_position,
/**< Position des Slaves im Bus */
uint16_t offset,
/**< Physikalische Speicheradresse im Slave */
unsigned int length
/**< Länge der zu lesenden Daten */
)
{
EC_FUNC_HEADER;
frame->type = ec_frame_type_aprd;
frame->address.physical.slave = (int16_t) ring_position * (-1);
frame->address.physical.mem = offset;
EC_FUNC_READ_FOOTER;
}
/*****************************************************************************/
/**
Initialisiert ein EtherCAT-APWR-Kommando.
Autoincrement physical write.
*/
void ec_frame_init_apwr(ec_frame_t *frame,
/**< EtherCAT-Rahmen */
ec_master_t *master,
/**< EtherCAT-Master */
uint16_t ring_position,
/**< Position des Slaves im Bus */
uint16_t offset,
/**< Physikalische Speicheradresse im Slave */
unsigned int length,
/**< Länge der zu schreibenden Daten */
const uint8_t *data
/**< Zeiger auf Speicher mit zu schreibenden Daten */
)
{
EC_FUNC_HEADER;
frame->type = ec_frame_type_apwr;
frame->address.physical.slave = (int16_t) ring_position * (-1);
frame->address.physical.mem = offset;
EC_FUNC_WRITE_FOOTER;
}
/*****************************************************************************/
/**
Initialisiert ein EtherCAT-BRD-Kommando.
Broadcast read.
*/
void ec_frame_init_brd(ec_frame_t *frame,
/**< EtherCAT-Rahmen */
ec_master_t *master,
/**< EtherCAT-Master */
uint16_t offset,
/**< Physikalische Speicheradresse im Slave */
unsigned int length
/**< Länge der zu lesenden Daten */
)
{
EC_FUNC_HEADER;
frame->type = ec_frame_type_brd;
frame->address.physical.slave = 0x0000;
frame->address.physical.mem = offset;
EC_FUNC_READ_FOOTER;
}
/*****************************************************************************/
/**
Initialisiert ein EtherCAT-BWR-Kommando.
Broadcast write.
*/
void ec_frame_init_bwr(ec_frame_t *frame,
/**< EtherCAT-Rahmen */
ec_master_t *master,
/**< EtherCAT-Master */
uint16_t offset,
/**< Physikalische Speicheradresse im Slave */
unsigned int length,
/**< Länge der zu schreibenden Daten */
const uint8_t *data
/**< Zeiger auf Speicher mit zu schreibenden Daten */
)
{
EC_FUNC_HEADER;
frame->type = ec_frame_type_bwr;
frame->address.physical.slave = 0x0000;
frame->address.physical.mem = offset;
EC_FUNC_WRITE_FOOTER;
}
/*****************************************************************************/
/**
Initialisiert ein EtherCAT-LRW-Kommando.
Logical read write.
*/
void ec_frame_init_lrw(ec_frame_t *frame,
/**< EtherCAT-Rahmen */
ec_master_t *master,
/**< EtherCAT-Master */
uint32_t offset,
/**< Logische Startadresse */
unsigned int length,
/**< Länge der zu lesenden/schreibenden Daten */
uint8_t *data
/**< Zeiger auf die Daten */
)
{
EC_FUNC_HEADER;
frame->type = ec_frame_type_lrw;
frame->address.logical = offset;
EC_FUNC_WRITE_FOOTER;
}
/*****************************************************************************/
/**
Sendet einen einzelnen EtherCAT-Rahmen.
\return 0 bei Erfolg, sonst < 0
*/
int ec_frame_send(ec_frame_t *frame /**< Rahmen zum Senden */)
{
unsigned int command_size, frame_size, i;
uint8_t *data;
if (unlikely(!frame->master->device.link_state))
return -1;
if (unlikely(frame->master->debug_level > 0)) {
EC_DBG("ec_frame_send\n");
}
command_size = frame->data_length + EC_COMMAND_HEADER_SIZE
+ EC_COMMAND_FOOTER_SIZE;
frame_size = command_size + EC_FRAME_HEADER_SIZE;
if (unlikely(frame_size > EC_MAX_FRAME_SIZE)) {
EC_ERR("Frame too long (%i)!\n", frame_size);
return -1;
}
if (frame_size < EC_MIN_FRAME_SIZE) frame_size = EC_MIN_FRAME_SIZE;
if (unlikely(frame->master->debug_level > 0)) {
EC_DBG("Frame length: %i\n", frame_size);
}
frame->index = frame->master->command_index;
frame->master->command_index = (frame->master->command_index + 1) % 0x0100;
if (unlikely(frame->master->debug_level > 0)) {
EC_DBG("Sending command index 0x%X\n", frame->index);
}
// Zeiger auf Socket-Buffer holen
data = ec_device_prepare(&frame->master->device);
// EtherCAT frame header
EC_WRITE_U16(data, (command_size & 0x7FF) | 0x1000);
data += EC_FRAME_HEADER_SIZE;
// EtherCAT command header
EC_WRITE_U8 (data, frame->type);
EC_WRITE_U8 (data + 1, frame->index);
EC_WRITE_U32(data + 2, frame->address.logical);
EC_WRITE_U16(data + 6, frame->data_length & 0x7FF);
EC_WRITE_U16(data + 8, 0x0000);
data += EC_COMMAND_HEADER_SIZE;
// EtherCAT command data
memcpy(data, frame->data, frame->data_length);
data += frame->data_length;
// EtherCAT command footer
EC_WRITE_U16(data, frame->working_counter);
data += EC_COMMAND_FOOTER_SIZE;
// Pad with zeros
for (i = EC_FRAME_HEADER_SIZE + EC_COMMAND_HEADER_SIZE
+ frame->data_length + EC_COMMAND_FOOTER_SIZE;
i < EC_MIN_FRAME_SIZE; i++)
EC_WRITE_U8(data++, 0x00);
// Send frame
ec_device_send(&frame->master->device, frame_size);
return 0;
}
/*****************************************************************************/
/**
Wertet empfangene Daten zu einem Rahmen aus.
\return 0 bei Erfolg, sonst < 0
*/
int ec_frame_receive(ec_frame_t *frame /**< Gesendeter Rahmen */)
{
unsigned int received_length, frame_length, data_length;
uint8_t *data;
uint8_t command_type, command_index;
ec_device_t *device;
device = &frame->master->device;
if (!(received_length = ec_device_received(device))) return -1;
device->state = EC_DEVICE_STATE_READY;
if (unlikely(received_length < EC_FRAME_HEADER_SIZE)) {
EC_ERR("Received frame with incomplete EtherCAT frame header!\n");
ec_device_debug(device);
return -1;
}
data = ec_device_data(device);
// Länge des gesamten Frames prüfen
frame_length = EC_READ_U16(data) & 0x07FF;
data += EC_FRAME_HEADER_SIZE;
if (unlikely(frame_length > received_length)) {
EC_ERR("Received corrupted frame (length does not match)!\n");
ec_device_debug(device);
return -1;
}
// Command header
command_type = EC_READ_U8(data);
command_index = EC_READ_U8(data + 1);
data_length = EC_READ_U16(data + 6) & 0x07FF;
data += EC_COMMAND_HEADER_SIZE;
if (unlikely(EC_FRAME_HEADER_SIZE + EC_COMMAND_HEADER_SIZE
+ data_length + EC_COMMAND_FOOTER_SIZE > received_length)) {
EC_ERR("Received frame with incomplete command data!\n");
ec_device_debug(device);
return -1;
}
if (unlikely(frame->type != command_type
|| frame->index != command_index
|| frame->data_length != data_length))
{
EC_WARN("WARNING - Send/Receive anomaly!\n");
ec_device_debug(device);
ec_device_call_isr(device); // Empfangenes "vergessen"
return -1;
}
// Empfangene Daten in Kommandodatenspeicher kopieren
memcpy(frame->data, data, data_length);
data += data_length;
// Working-Counter setzen
frame->working_counter = EC_READ_U16(data);
return 0;
}
/*****************************************************************************/
/**
Sendet einen einzeln Rahmen und wartet auf dessen Empfang.
Wenn der Working-Counter nicht gesetzt wurde, wird der Rahmen
nochmals gesendet.
\todo Das ist noch nicht schön, da hier zwei Protokollschichten
vermischt werden.
\return 0 bei Erfolg, sonst < 0
*/
int ec_frame_send_receive(ec_frame_t *frame
/**< Rahmen zum Senden/Empfangen */
)
{
unsigned int timeout_tries_left, response_tries_left;
unsigned int tries;
tries = 0;
response_tries_left = 10;
do
{
tries++;
if (unlikely(ec_frame_send(frame) < 0)) {
EC_ERR("Frame sending failed!\n");
return -1;
}
timeout_tries_left = 20;
do
{
udelay(1);
ec_device_call_isr(&frame->master->device);
timeout_tries_left--;
}
while (unlikely(!ec_device_received(&frame->master->device)
&& timeout_tries_left));
if (unlikely(!timeout_tries_left)) {
EC_ERR("Frame timeout!\n");
return -1;
}
if (unlikely(ec_frame_receive(frame) < 0)) {
EC_ERR("Frame receiving failed!\n");
return -1;
}
response_tries_left--;
}
while (unlikely(!frame->working_counter && response_tries_left));
if (unlikely(!response_tries_left)) {
EC_ERR("No response!");
return -1;
}
if (tries > 1) EC_WARN("%i tries necessary...\n", tries);
return 0;
}
/*****************************************************************************/
/* Emacs-Konfiguration
;;; Local Variables: ***
;;; c-basic-offset:4 ***
;;; End: ***
*/

View File

@@ -1,111 +0,0 @@
/******************************************************************************
*
* f r a m e . h
*
* Struktur für einen EtherCAT-Rahmen.
*
* $Id$
*
*****************************************************************************/
#ifndef _EC_FRAME_H_
#define _EC_FRAME_H_
#include "globals.h"
#include "../include/EtherCAT_rt.h"
/*****************************************************************************/
/**
EtherCAT-Rahmen-Typ
*/
typedef enum
{
ec_frame_type_none = 0x00, /**< Dummy */
ec_frame_type_aprd = 0x01, /**< Auto-increment physical read */
ec_frame_type_apwr = 0x02, /**< Auto-increment physical write */
ec_frame_type_nprd = 0x04, /**< Node-addressed physical read */
ec_frame_type_npwr = 0x05, /**< Node-addressed physical write */
ec_frame_type_brd = 0x07, /**< Broadcast read */
ec_frame_type_bwr = 0x08, /**< Broadcast write */
ec_frame_type_lrw = 0x0C /**< Logical read/write */
}
ec_frame_type_t;
/*****************************************************************************/
/**
EtherCAT-Adresse.
Im EtherCAT-Rahmen sind 4 Bytes für die Adresse reserviert, die je nach
Kommandotyp, eine andere Bedeutung haben können: Bei Autoinkrementbefehlen
sind die ersten zwei Bytes die (negative) Autoinkrement-Adresse, bei Knoten-
adressierten Befehlen entsprechen sie der Knotenadresse. Das dritte und
vierte Byte entspricht in diesen Fällen der physikalischen Speicheradresse
auf dem Slave. Bei einer logischen Adressierung entsprechen alle vier Bytes
der logischen Adresse.
*/
typedef union
{
struct
{
uint16_t slave; /**< Adresse des Slaves (Ringposition oder Knoten) */
uint16_t mem; /**< Physikalische Speicheradresse im Slave */
}
physical; /**< Physikalische Adresse */
uint32_t logical; /**< Logische Adresse */
}
ec_address_t;
/*****************************************************************************/
/**
EtherCAT-Frame.
*/
typedef struct
{
ec_master_t *master; /**< EtherCAT-Master */
ec_frame_type_t type; /**< Typ des Frames (APRD, NPWR, etc) */
ec_address_t address; /**< Adresse des/der Empfänger */
unsigned int data_length; /**< Länge der zu sendenden und/oder empfangenen
Daten */
uint8_t index; /**< Kommando-Index, mit dem der Frame gesendet wurde
(wird vom Master beim Senden gesetzt). */
uint16_t working_counter; /**< Working-Counter */
uint8_t data[EC_MAX_FRAME_SIZE]; /**< Rahmendaten */
}
ec_frame_t;
/*****************************************************************************/
void ec_frame_init_nprd(ec_frame_t *, ec_master_t *, uint16_t, uint16_t,
unsigned int);
void ec_frame_init_npwr(ec_frame_t *, ec_master_t *, uint16_t, uint16_t,
unsigned int, const unsigned char *);
void ec_frame_init_aprd(ec_frame_t *, ec_master_t *, uint16_t, uint16_t,
unsigned int);
void ec_frame_init_apwr(ec_frame_t *, ec_master_t *, uint16_t, uint16_t,
unsigned int, const unsigned char *);
void ec_frame_init_brd(ec_frame_t *, ec_master_t *, uint16_t, unsigned int);
void ec_frame_init_bwr(ec_frame_t *, ec_master_t *, uint16_t, unsigned int,
const unsigned char *);
void ec_frame_init_lrw(ec_frame_t *, ec_master_t *, uint32_t, unsigned int,
unsigned char *);
int ec_frame_send(ec_frame_t *);
int ec_frame_receive(ec_frame_t *);
int ec_frame_send_receive(ec_frame_t *);
/*****************************************************************************/
#endif
/* Emacs-Konfiguration
;;; Local Variables: ***
;;; c-basic-offset:4 ***
;;; End: ***
*/

View File

@@ -15,7 +15,7 @@
// EtherCAT-Protokoll
#define EC_MAX_FRAME_SIZE 1500 /**< Maximale Größe eines EtherCAT-Frames ohne
Ethernet-II-Header und -Prüfsumme*/
Ethernet-II-Header und -Prüfsumme */
#define EC_MIN_FRAME_SIZE 46 /** Minimale Größe, s. o. */
#define EC_FRAME_HEADER_SIZE 2 /**< Größe des EtherCAT-Frame-Headers */
#define EC_COMMAND_HEADER_SIZE 10 /**< Größe eines EtherCAT-Kommando-Headers */
@@ -43,28 +43,6 @@
/*****************************************************************************/
/**
Zustand eines EtherCAT-Slaves
*/
typedef enum
{
EC_SLAVE_STATE_UNKNOWN = 0x00, /**< Status unbekannt */
EC_SLAVE_STATE_INIT = 0x01, /**< Init-Zustand (Keine Mailbox-
Kommunikation, Kein I/O) */
EC_SLAVE_STATE_PREOP = 0x02, /**< Pre-Operational (Mailbox-
Kommunikation, Kein I/O) */
EC_SLAVE_STATE_SAVEOP = 0x04, /**< Save-Operational (Mailbox-
Kommunikation und Input Update) */
EC_SLAVE_STATE_OP = 0x08, /**< Operational, (Mailbox-
Kommunikation und Input/Output Update) */
EC_ACK = 0x10 /**< Acknoledge-Bit beim Zustandswechsel
(dies ist kein eigener Zustand) */
}
ec_slave_state_t;
/*****************************************************************************/
#endif
/* Emacs-Konfiguration

File diff suppressed because it is too large Load Diff

View File

@@ -15,11 +15,26 @@
#include "device.h"
#include "slave.h"
#include "frame.h"
#include "domain.h"
/*****************************************************************************/
/**
EtherCAT-Rahmen-Statistiken.
*/
typedef struct
{
unsigned int timeouts; /**< Kommando-Timeouts */
unsigned int delayed; /**< Verzögerte Kommandos */
unsigned int corrupted; /**< Verfälschte Rahmen */
unsigned int unmatched; /**< Unpassende Kommandos */
cycles_t t_last; /**< Timestamp-Counter bei der letzten Ausgabe */
}
ec_stats_t;
/*****************************************************************************/
/**
EtherCAT-Master
@@ -31,16 +46,12 @@ struct ec_master
{
ec_slave_t *slaves; /**< Array von Slaves auf dem Bus */
unsigned int slave_count; /**< Anzahl Slaves auf dem Bus */
ec_device_t device; /**< EtherCAT-Gerät */
unsigned int device_registered; /**< Ein Geraet hat sich registriert. */
ec_device_t *device; /**< EtherCAT-Gerät */
struct list_head commands; /**< Kommando-Liste */
uint8_t command_index; /**< Aktueller Kommando-Index */
struct list_head domains; /**< Liste der Prozessdatendomänen */
int debug_level; /**< Debug-Level im Master-Code */
unsigned int bus_time; /**< Letzte Bus-Zeit in Mikrosekunden */
unsigned int frames_lost; /**< Anzahl verlorener Frames */
unsigned int frames_delayed; /**< Anzahl verzögerter Frames */
unsigned long t_last_cyclic_output; /**< Timer-Ticks bei den letzten
zyklischen Ausgaben */
ec_stats_t stats; /**< Rahmen-Statistiken */
};
/*****************************************************************************/
@@ -49,19 +60,23 @@ struct ec_master
void ec_master_init(ec_master_t *);
void ec_master_clear(ec_master_t *);
void ec_master_reset(ec_master_t *);
void ec_master_clear_slaves(ec_master_t *);
// IO
void ec_master_receive(ec_master_t *, const uint8_t *, size_t);
void ec_master_queue_command(ec_master_t *, ec_command_t *);
int ec_master_simple_io(ec_master_t *, ec_command_t *);
// Registration of devices
int ec_master_open(ec_master_t *);
void ec_master_close(ec_master_t *);
// Slave management
int ec_scan_for_slaves(ec_master_t *);
ec_slave_t *ec_address(const ec_master_t *, const char *);
int ec_master_bus_scan(ec_master_t *);
ec_slave_t *ec_master_slave_address(const ec_master_t *, const char *);
// Misc
void ec_output_debug_data(const ec_master_t *);
void ec_cyclic_output(ec_master_t *);
void ec_master_debug(const ec_master_t *);
void ec_master_output_stats(ec_master_t *);
/*****************************************************************************/

View File

@@ -35,9 +35,9 @@ void __exit ec_cleanup_module(void);
#define EC_LIT(X) #X
#define EC_STR(X) EC_LIT(X)
#define COMPILE_INFO "Revision " EC_STR(EC_REV) \
", compiled by " EC_STR(EC_USER) \
" at " EC_STR(EC_DATE)
#define COMPILE_INFO "Revision " EC_STR(SVNREV) \
", compiled by " EC_STR(USER) \
" at " __DATE__ " " __TIME__
/*****************************************************************************/
@@ -155,38 +155,35 @@ ec_device_t *EtherCAT_dev_register(unsigned int master_index,
/**< Zeiger auf das Modul */
)
{
ec_device_t *device;
ec_master_t *master;
if (master_index >= ec_master_count) {
EC_ERR("Master %i does not exist!\n", master_index);
return NULL;
}
if (!net_dev) {
EC_WARN("Device is NULL!\n");
return NULL;
}
if (master_index >= ec_master_count) {
EC_ERR("Master %i does not exist!\n", master_index);
return NULL;
}
master = ec_masters + master_index;
if (master->device_registered) {
if (master->device) {
EC_ERR("Master %i already has a device!\n", master_index);
return NULL;
}
device = &master->device;
if (!(master->device = (ec_device_t *) kmalloc(sizeof(ec_device_t),
GFP_KERNEL))) {
EC_ERR("Failed allocating device!\n");
return NULL;
}
if (ec_device_init(device, master) < 0) return NULL;
if (ec_device_init(master->device, master, net_dev, isr, module))
return NULL;
device->dev = net_dev;
device->tx_skb->dev = net_dev;
device->isr = isr;
device->module = module;
master->device_registered = 1;
return device;
return master->device;
}
/*****************************************************************************/
@@ -210,13 +207,14 @@ void EtherCAT_dev_unregister(unsigned int master_index,
master = ec_masters + master_index;
if (!master->device_registered || &master->device != device) {
if (!master->device || master->device != device) {
EC_WARN("Unable to unregister device!\n");
return;
}
master->device_registered = 0;
ec_device_clear(device);
ec_device_clear(master->device);
kfree(master->device);
master->device = NULL;
}
/******************************************************************************
@@ -253,22 +251,24 @@ ec_master_t *EtherCAT_rt_request_master(unsigned int index
master = &ec_masters[index];
if (!master->device_registered) {
if (!master->device) {
EC_ERR("Master %i has no device assigned yet!\n", index);
goto req_return;
}
if (!try_module_get(master->device.module)) {
if (!try_module_get(master->device->module)) {
EC_ERR("Failed to reserve device module!\n");
goto req_return;
}
if (ec_master_open(master) < 0) {
if (ec_master_open(master)) {
EC_ERR("Failed to open device!\n");
goto req_module_put;
}
if (ec_scan_for_slaves(master) != 0) {
if (!master->device->link_state) EC_WARN("Link is DOWN.\n");
if (ec_master_bus_scan(master) != 0) {
EC_ERR("Bus scan failed!\n");
goto req_close;
}
@@ -282,7 +282,7 @@ ec_master_t *EtherCAT_rt_request_master(unsigned int index
ec_master_close(master);
req_module_put:
module_put(master->device.module);
module_put(master->device->module);
ec_master_reset(master);
req_return:
@@ -318,7 +318,7 @@ void EtherCAT_rt_release_master(ec_master_t *master /**< EtherCAT-Masdter */)
ec_master_close(master);
ec_master_reset(master);
module_put(master->device.module);
module_put(master->device->module);
ec_masters_reserved[i] = 0;
EC_INFO("===== Master %i stopped. =====\n", i);

View File

@@ -14,7 +14,8 @@
#include "../include/EtherCAT_si.h"
#include "globals.h"
#include "slave.h"
#include "frame.h"
#include "command.h"
#include "master.h"
/*****************************************************************************/
@@ -64,23 +65,21 @@ void ec_slave_clear(ec_slave_t *slave /**< EtherCAT-Slave */)
int ec_slave_fetch(ec_slave_t *slave /**< EtherCAT-Slave */)
{
ec_frame_t frame;
ec_command_t command;
// Read base data
ec_frame_init_nprd(&frame, slave->master, slave->station_address,
0x0000, 6);
if (unlikely(ec_frame_send_receive(&frame))) {
ec_command_init_nprd(&command, slave->station_address, 0x0000, 6);
if (unlikely(ec_master_simple_io(slave->master, &command))) {
EC_ERR("Reading base datafrom slave %i failed!\n",
slave->ring_position);
return -1;
}
slave->base_type = EC_READ_U8 (frame.data);
slave->base_revision = EC_READ_U8 (frame.data + 1);
slave->base_build = EC_READ_U16(frame.data + 2);
slave->base_fmmu_count = EC_READ_U8 (frame.data + 4);
slave->base_sync_count = EC_READ_U8 (frame.data + 5);
slave->base_type = EC_READ_U8 (command.data);
slave->base_revision = EC_READ_U8 (command.data + 1);
slave->base_build = EC_READ_U16(command.data + 2);
slave->base_fmmu_count = EC_READ_U8 (command.data + 4);
slave->base_sync_count = EC_READ_U8 (command.data + 5);
if (slave->base_fmmu_count > EC_MAX_FMMUS)
slave->base_fmmu_count = EC_MAX_FMMUS;
@@ -130,9 +129,9 @@ int ec_slave_sii_read(ec_slave_t *slave,
der Daten */
)
{
ec_frame_t frame;
ec_command_t command;
unsigned char data[10];
unsigned int tries_left;
cycles_t start, end, timeout;
// Initiate read operation
@@ -141,10 +140,8 @@ int ec_slave_sii_read(ec_slave_t *slave,
EC_WRITE_U16(data + 2, offset);
EC_WRITE_U16(data + 4, 0x0000);
ec_frame_init_npwr(&frame, slave->master, slave->station_address,
0x502, 6, data);
if (unlikely(ec_frame_send_receive(&frame))) {
ec_command_init_npwr(&command, slave->station_address, 0x502, 6, data);
if (unlikely(ec_master_simple_io(slave->master, &command))) {
EC_ERR("SII-read failed on slave %i!\n", slave->ring_position);
return -1;
}
@@ -153,29 +150,28 @@ int ec_slave_sii_read(ec_slave_t *slave,
// in das Datenregister und löscht daraufhin ein Busy-Bit. Solange
// den Status auslesen, bis das Bit weg ist.
tries_left = 100;
while (likely(tries_left))
start = get_cycles();
timeout = cpu_khz; // 1ms
do
{
udelay(10);
ec_frame_init_nprd(&frame, slave->master, slave->station_address,
0x502, 10);
if (unlikely(ec_frame_send_receive(&frame))) {
ec_command_init_nprd(&command, slave->station_address, 0x502, 10);
if (unlikely(ec_master_simple_io(slave->master, &command))) {
EC_ERR("Getting SII-read status failed on slave %i!\n",
slave->ring_position);
return -1;
}
if (likely((EC_READ_U8(frame.data + 1) & 0x81) == 0)) {
memcpy(target, frame.data + 6, 4);
end = get_cycles();
if (likely((EC_READ_U8(command.data + 1) & 0x81) == 0)) {
memcpy(target, command.data + 6, 4);
break;
}
tries_left--;
}
while (likely((end - start) < timeout));
if (unlikely(!tries_left)) {
if (unlikely((end - start) >= timeout)) {
EC_ERR("SSI-read. Slave %i timed out!\n", slave->ring_position);
return -1;
}
@@ -197,52 +193,49 @@ void ec_slave_state_ack(ec_slave_t *slave,
/**< Alter Zustand */
)
{
ec_frame_t frame;
ec_command_t command;
unsigned char data[2];
unsigned int tries_left;
cycles_t start, end, timeout;
EC_WRITE_U16(data, state | EC_ACK);
ec_frame_init_npwr(&frame, slave->master, slave->station_address,
0x0120, 2, data);
if (unlikely(ec_frame_send_receive(&frame))) {
ec_command_init_npwr(&command, slave->station_address, 0x0120, 2, data);
if (unlikely(ec_master_simple_io(slave->master, &command))) {
EC_WARN("State %02X acknowledge failed on slave %i!\n",
state, slave->ring_position);
return;
}
tries_left = 100;
while (likely(tries_left))
start = get_cycles();
timeout = cpu_khz; // 1ms
do
{
udelay(10);
ec_frame_init_nprd(&frame, slave->master, slave->station_address,
0x0130, 2);
if (unlikely(ec_frame_send_receive(&frame))) {
ec_command_init_nprd(&command, slave->station_address, 0x0130, 2);
if (unlikely(ec_master_simple_io(slave->master, &command))) {
EC_WARN("State %02X acknowledge checking failed on slave %i!\n",
state, slave->ring_position);
return;
}
if (unlikely(EC_READ_U8(frame.data) != state)) {
end = get_cycles();
if (unlikely(EC_READ_U8(command.data) != state)) {
EC_WARN("Could not acknowledge state %02X on slave %i (code"
" %02X)!\n", state, slave->ring_position,
EC_READ_U8(frame.data));
EC_READ_U8(command.data));
return;
}
if (likely(EC_READ_U8(frame.data) == state)) {
if (likely(EC_READ_U8(command.data) == state)) {
EC_INFO("Acknowleged state %02X on slave %i.\n", state,
slave->ring_position);
return;
}
tries_left--;
}
while (likely((end - start) < timeout));
if (unlikely(!tries_left)) {
if (unlikely((end - start) >= timeout)) {
EC_WARN("Could not check state acknowledgement %02X of slave %i -"
" Timeout while checking!\n", state, slave->ring_position);
return;
@@ -263,52 +256,51 @@ int ec_slave_state_change(ec_slave_t *slave,
/**< Neuer Zustand */
)
{
ec_frame_t frame;
ec_command_t command;
unsigned char data[2];
unsigned int tries_left;
cycles_t start, end, timeout;
EC_WRITE_U16(data, state);
ec_frame_init_npwr(&frame, slave->master, slave->station_address,
0x0120, 2, data);
if (unlikely(ec_frame_send_receive(&frame))) {
ec_command_init_npwr(&command, slave->station_address, 0x0120, 2, data);
if (unlikely(ec_master_simple_io(slave->master, &command))) {
EC_ERR("Failed to set state %02X on slave %i!\n",
state, slave->ring_position);
return -1;
}
tries_left = 100;
while (likely(tries_left))
start = get_cycles();
timeout = cpu_khz; // 1ms
do
{
udelay(10);
udelay(100); // Dem Slave etwas Zeit lassen...
ec_frame_init_nprd(&frame, slave->master, slave->station_address,
0x0130, 2);
if (unlikely(ec_frame_send_receive(&frame))) {
ec_command_init_nprd(&command, slave->station_address, 0x0130, 2);
if (unlikely(ec_master_simple_io(slave->master, &command))) {
EC_ERR("Failed to check state %02X on slave %i!\n",
state, slave->ring_position);
return -1;
}
if (unlikely(EC_READ_U8(frame.data) & 0x10)) { // State change error
end = get_cycles();
if (unlikely(EC_READ_U8(command.data) & 0x10)) { // State change error
EC_ERR("Could not set state %02X - Slave %i refused state change"
" (code %02X)!\n", state, slave->ring_position,
EC_READ_U8(frame.data));
ec_slave_state_ack(slave, EC_READ_U8(frame.data) & 0x0F);
EC_READ_U8(command.data));
ec_slave_state_ack(slave, EC_READ_U8(command.data) & 0x0F);
return -1;
}
if (likely(EC_READ_U8(frame.data) == (state & 0x0F))) {
if (likely(EC_READ_U8(command.data) == (state & 0x0F))) {
// State change successful
break;
}
tries_left--;
}
while (likely((end - start) < timeout));
if (unlikely(!tries_left)) {
if (unlikely((end - start) >= timeout)) {
EC_ERR("Could not check state %02X of slave %i - Timeout!\n", state,
slave->ring_position);
return -1;
@@ -405,31 +397,27 @@ void ec_slave_print(const ec_slave_t *slave /**< EtherCAT-Slave */)
int ec_slave_check_crc(ec_slave_t *slave /**< EtherCAT-Slave */)
{
ec_frame_t frame;
ec_command_t command;
uint8_t data[4];
ec_frame_init_nprd(&frame, slave->master, slave->station_address,
0x0300, 4);
if (unlikely(ec_frame_send_receive(&frame))) {
ec_command_init_nprd(&command, slave->station_address, 0x0300, 4);
if (unlikely(ec_master_simple_io(slave->master, &command))) {
EC_WARN("Reading CRC fault counters failed on slave %i!\n",
slave->ring_position);
return -1;
}
// No CRC faults.
if (!EC_READ_U16(frame.data) && !EC_READ_U16(frame.data + 2)) return 0;
if (!EC_READ_U16(command.data) && !EC_READ_U16(command.data + 2)) return 0;
EC_WARN("CRC faults on slave %i. A: %i, B: %i\n", slave->ring_position,
EC_READ_U16(frame.data), EC_READ_U16(frame.data + 2));
EC_READ_U16(command.data), EC_READ_U16(command.data + 2));
// Reset CRC counters
EC_WRITE_U16(data, 0x0000);
EC_WRITE_U16(data + 2, 0x0000);
ec_frame_init_npwr(&frame, slave->master, slave->station_address,
0x0300, 4, data);
if (unlikely(ec_frame_send_receive(&frame))) {
ec_command_init_npwr(&command, slave->station_address, 0x0300, 4, data);
if (unlikely(ec_master_simple_io(slave->master, &command))) {
EC_WARN("Resetting CRC fault counters failed on slave %i!\n",
slave->ring_position);
return -1;

View File

@@ -15,6 +15,28 @@
/*****************************************************************************/
/**
Zustand eines EtherCAT-Slaves.
*/
typedef enum
{
EC_SLAVE_STATE_UNKNOWN = 0x00, /**< Status unbekannt */
EC_SLAVE_STATE_INIT = 0x01, /**< Init-Zustand (Keine Mailbox-
Kommunikation, Kein I/O) */
EC_SLAVE_STATE_PREOP = 0x02, /**< Pre-Operational (Mailbox-
Kommunikation, Kein I/O) */
EC_SLAVE_STATE_SAVEOP = 0x04, /**< Save-Operational (Mailbox-
Kommunikation und Input Update) */
EC_SLAVE_STATE_OP = 0x08, /**< Operational, (Mailbox-
Kommunikation und Input/Output Update) */
EC_ACK = 0x10 /**< Acknoledge-Bit beim Zustandswechsel
(dies ist kein eigener Zustand) */
}
ec_slave_state_t;
/*****************************************************************************/
/**
FMMU-Konfiguration.
*/

View File

@@ -17,7 +17,7 @@
/*****************************************************************************/
#define ABTASTFREQUENZ 1000
#define ABTASTFREQUENZ 100
struct timer_list timer;
@@ -47,7 +47,9 @@ void run(unsigned long data)
static unsigned int counter = 0;
// Prozessdaten lesen und schreiben
EtherCAT_rt_domain_xio(domain1);
EtherCAT_rt_domain_queue(domain1);
EtherCAT_rt_master_xio(master);
EtherCAT_rt_domain_process(domain1);
k_angle = EC_READ_U16(r_inc);
k_pos = EC_READ_U32(r_ssi);

View File

@@ -28,8 +28,9 @@ msr_modul-objs := msr_module.o \
rt_lib/msr-math/msr_hex_bin.o \
libm.o
EXTRA_CFLAGS := -I $(src)/rt_lib/msr-include -D_SIMULATION \
-I/usr/include -mhard-float
EXTRA_CFLAGS := -I$(src)/rt_lib/msr-include -D_SIMULATION \
-I/usr/include -mhard-float \
-DSVNREV=$(shell svnversion $(src)) -DUSER=$(USER)
#------------------------------------------------------------------------------

View File

@@ -50,9 +50,11 @@ static struct ipipe_sysinfo sys_info;
// EtherCAT
ec_master_t *master = NULL;
ec_domain_t *domain1 = NULL;
ec_domain_t *domain2 = NULL;
// Prozessdaten
void *r_ssi;
void *r_ssi2;
void *r_inc;
uint32_t k_angle;
@@ -60,7 +62,11 @@ uint32_t k_pos;
ec_field_init_t domain1_fields[] = {
{&r_ssi, "1", "Beckhoff", "EL5001", ec_ipvalue, 0, 1},
{&r_inc, "10", "Beckhoff", "EL5101", ec_ipvalue, 0, 1},
{}
};
ec_field_init_t domain2_fields[] = {
{&r_ssi2, "1", "Beckhoff", "EL5001", ec_ipvalue, 0, 1},
{}
};
@@ -68,11 +74,27 @@ ec_field_init_t domain1_fields[] = {
static void msr_controller_run(void)
{
// Prozessdaten lesen und schreiben
EtherCAT_rt_domain_xio(domain1);
static unsigned int counter = 0;
k_angle = EC_READ_U16(r_inc);
if (counter) counter--;
else {
//EtherCAT_rt_master_debug(master, 2);
counter = MSR_ABTASTFREQUENZ;
}
// Prozessdaten lesen und schreiben
EtherCAT_rt_domain_queue(domain1);
EtherCAT_rt_domain_queue(domain2);
EtherCAT_rt_master_xio(master);
EtherCAT_rt_domain_process(domain1);
EtherCAT_rt_domain_process(domain2);
//k_angle = EC_READ_U16(r_inc);
k_pos = EC_READ_U32(r_ssi);
//EtherCAT_rt_master_debug(master, 0);
}
/*****************************************************************************/
@@ -118,7 +140,6 @@ void domain_entry(void)
int __init init_rt_module(void)
{
struct ipipe_domain_attr attr; //ipipe
const ec_field_init_t *field;
uint32_t version;
// Als allererstes die RT-lib initialisieren
@@ -134,7 +155,7 @@ int __init init_rt_module(void)
//EtherCAT_rt_master_print(master);
printk(KERN_INFO "Registering domain...\n");
printk(KERN_INFO "Registering domains...\n");
if (!(domain1 = EtherCAT_rt_master_register_domain(master, ec_sync, 100)))
{
@@ -142,32 +163,37 @@ int __init init_rt_module(void)
goto out_release_master;
}
if (!(domain2 = EtherCAT_rt_master_register_domain(master, ec_sync, 100)))
{
printk(KERN_ERR "EtherCAT: Could not register domain!\n");
goto out_release_master;
}
printk(KERN_INFO "Registering domain fields...\n");
for (field = domain1_fields; field->data; field++)
{
if (!EtherCAT_rt_register_slave_field(domain1,
field->address,
field->vendor,
field->product,
field->data,
field->field_type,
field->field_index,
field->field_count)) {
printk(KERN_ERR "Could not register field!\n");
goto out_release_master;
}
if (EtherCAT_rt_register_domain_fields(domain1, domain1_fields)) {
printk(KERN_ERR "Failed to register domain fields.\n");
goto out_release_master;
}
if (EtherCAT_rt_register_domain_fields(domain2, domain2_fields)) {
printk(KERN_ERR "Failed to register domain fields.\n");
goto out_release_master;
}
printk(KERN_INFO "Activating master...\n");
//EtherCAT_rt_master_debug(master, 2);
if (EtherCAT_rt_master_activate(master)) {
printk(KERN_ERR "Could not activate master!\n");
goto out_release_master;
}
//EtherCAT_rt_master_debug(master, 0);
#if 1
if (EtherCAT_rt_canopen_sdo_addr_read(master, "1", 0x100A, 1,
if (EtherCAT_rt_canopen_sdo_addr_read(master, "6", 0x100A, 1,
&version)) {
printk(KERN_ERR "Could not read SSI version!\n");
goto out_release_master;
@@ -222,9 +248,16 @@ void __exit cleanup_rt_module(void)
/*****************************************************************************/
#define EC_LIT(X) #X
#define EC_STR(X) EC_LIT(X)
#define COMPILE_INFO "Revision " EC_STR(SVNREV) \
", compiled by " EC_STR(USER) \
" at " __DATE__ " " __TIME__
MODULE_LICENSE("GPL");
MODULE_AUTHOR ("Florian Pose <fp@igh-essen.com>");
MODULE_DESCRIPTION ("EtherCAT real-time test environment");
MODULE_VERSION(COMPILE_INFO);
module_init(init_rt_module);
module_exit(cleanup_rt_module);