Dynamische FMMU-Konfiguration, zwei Kopieroperationen eingespart, Einrückungen angepasst.
This commit is contained in:
parent
30f4dfcc59
commit
4d65b22b0f
2
Makefile
2
Makefile
|
|
@ -42,6 +42,6 @@ config conf $(CONFIG_FILE):
|
|||
@echo >> $(CONFIG_FILE)
|
||||
@echo "$(CONFIG_FILE) erstellt."
|
||||
|
||||
#----------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
endif
|
||||
|
|
|
|||
1
TODO
1
TODO
|
|
@ -7,4 +7,5 @@ $Id$
|
|||
- Ethernet over EtherCAT (EoE)
|
||||
- eepro100-Kartentreiber
|
||||
- Proc/SysFS-Interface mit Baumdarstellung des Busses
|
||||
- Anzahl unterstützter Sync-Manager/FMMUs auslesen
|
||||
|
||||
|
|
|
|||
|
|
@ -2268,14 +2268,12 @@ no_early_rx:
|
|||
}
|
||||
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 @@ irqreturn_t rtl8139_interrupt (int irq, void *dev_instance,
|
|||
else
|
||||
{
|
||||
/* Beim EtherCAT-Device einfach alle Frames empfangen */
|
||||
rtl8139_rx(dev, tp, 100); // FIXME Das ist echt dirty...
|
||||
rtl8139_rx(dev, tp, 100); // FIXME
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,8 +21,11 @@ typedef struct ec_device ec_device_t;
|
|||
|
||||
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 @@ ec_device_t *EtherCAT_dev_register(unsigned int, struct net_device *,
|
|||
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);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ ifneq ($(KERNELRELEASE),)
|
|||
|
||||
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)`
|
||||
|
|
|
|||
|
|
@ -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 @@ int EtherCAT_rt_canopen_sdo_write(ec_master_t *master, ec_slave_t *slave,
|
|||
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 @@ int EtherCAT_rt_canopen_sdo_write(ec_master_t *master, ec_slave_t *slave,
|
|||
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 @@ int EtherCAT_rt_canopen_sdo_write(ec_master_t *master, ec_slave_t *slave,
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,3 +17,9 @@
|
|||
/*****************************************************************************/
|
||||
|
||||
#endif
|
||||
|
||||
/* Emacs-Konfiguration
|
||||
;;; Local Variables: ***
|
||||
;;; c-basic-offset:4 ***
|
||||
;;; End: ***
|
||||
*/
|
||||
|
|
|
|||
250
master/command.c
250
master/command.c
|
|
@ -1,250 +0,0 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* c o m m a n d . c
|
||||
*
|
||||
* Methoden für ein EtherCAT-Kommando.
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#include <linux/slab.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
102
master/command.h
102
master/command.h
|
|
@ -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
|
||||
329
master/device.c
329
master/device.c
|
|
@ -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;
|
||||
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(EC_FRAME_SIZE)) == NULL) {
|
||||
printk(KERN_ERR "EtherCAT: Could not allocate device tx socket buffer!\n");
|
||||
return -1;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -70,19 +60,14 @@ int ec_device_init(ec_device_t *ecd)
|
|||
|
||||
void ec_device_clear(ec_device_t *ecd)
|
||||
{
|
||||
if (ecd->open) ec_device_close(ecd);
|
||||
if (ecd->open) ec_device_close(ecd);
|
||||
|
||||
ecd->dev = NULL;
|
||||
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->tx_skb) {
|
||||
dev_kfree_skb(ecd->tx_skb);
|
||||
ecd->tx_skb = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -102,34 +87,32 @@ void ec_device_clear(ec_device_t *ecd)
|
|||
|
||||
int ec_device_open(ec_device_t *ecd)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int i;
|
||||
|
||||
if (!ecd) {
|
||||
printk(KERN_ERR "EtherCAT: Trying to open a NULL device!\n");
|
||||
return -1;
|
||||
}
|
||||
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->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);
|
||||
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;
|
||||
// Reset old device state
|
||||
ecd->state = EC_DEVICE_STATE_READY;
|
||||
|
||||
if (ecd->dev->open(ecd->dev) == 0) ecd->open = 1;
|
||||
}
|
||||
if (ecd->dev->open(ecd->dev) == 0) ecd->open = 1;
|
||||
}
|
||||
|
||||
return ecd->open ? 0 : -1;
|
||||
return ecd->open ? 0 : -1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -140,27 +123,42 @@ int ec_device_open(ec_device_t *ecd)
|
|||
@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->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->open) {
|
||||
printk(KERN_WARNING "EtherCAT: Device already closed!\n");
|
||||
}
|
||||
else {
|
||||
if (ecd->dev->stop(ecd->dev) == 0) ecd->open = 0;
|
||||
}
|
||||
|
||||
if (ecd->dev->stop(ecd->dev) == 0) ecd->open = 0;
|
||||
}
|
||||
return !ecd->open ? 0 : -1;
|
||||
}
|
||||
|
||||
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,100 +170,57 @@ int ec_device_close(ec_device_t *ecd)
|
|||
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)
|
||||
void ec_device_send(ec_device_t *ecd, /**< EtherCAT-Gerät */
|
||||
unsigned int length /**< Länge der zu sendenden Daten */
|
||||
)
|
||||
{
|
||||
unsigned char *frame_data;
|
||||
struct ethhdr *eth;
|
||||
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");
|
||||
}
|
||||
// Framegroesse auf (jetzt bekannte) Laenge abschneiden
|
||||
skb_trim(ecd->tx_skb, length);
|
||||
|
||||
// Clear transmit socket buffer and reserve
|
||||
// space for Ethernet-II header
|
||||
skb_trim(ecd->tx_skb, 0);
|
||||
skb_reserve(ecd->tx_skb, ETH_HLEN);
|
||||
// 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);
|
||||
|
||||
// Copy data to socket buffer
|
||||
frame_data = skb_put(ecd->tx_skb, length);
|
||||
memcpy(frame_data, data, length);
|
||||
ecd->state = EC_DEVICE_STATE_SENT;
|
||||
ecd->rx_data_length = 0;
|
||||
|
||||
// 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;
|
||||
// Senden einleiten
|
||||
rdtscl(ecd->tx_time); // Get CPU cycles
|
||||
ecd->dev->hard_start_xmit(ecd->tx_skb, ecd->dev);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Holt einen empfangenen Rahmen von der Netzwerkkarte.
|
||||
Gibt die Anzahl der empfangenen Bytes zurück.
|
||||
|
||||
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
|
||||
|
||||
@return Anzahl der kopierten Bytes bei Erfolg, sonst < 0
|
||||
\return Empfangene Bytes, oder 0, wenn kein Frame empfangen wurde.
|
||||
*/
|
||||
|
||||
int ec_device_receive(ec_device_t *ecd, unsigned char *data)
|
||||
unsigned int ec_device_received(const ec_device_t *ecd)
|
||||
{
|
||||
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;
|
||||
}
|
||||
return ecd->rx_data_length;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
/**
|
||||
Gibt die empfangenen Daten zurück.
|
||||
|
||||
memcpy(data, ecd->rx_data, ecd->rx_data_length);
|
||||
\return Adresse auf empfangene Daten.
|
||||
*/
|
||||
|
||||
return ecd->rx_data_length;
|
||||
uint8_t *ec_device_data(ec_device_t *ecd)
|
||||
{
|
||||
return ecd->rx_data;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -280,7 +235,7 @@ int ec_device_receive(ec_device_t *ecd, unsigned char *data)
|
|||
|
||||
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 @@ void ec_device_call_isr(ec_device_t *ecd)
|
|||
@param ecd EtherCAT-Gerät
|
||||
*/
|
||||
|
||||
void ec_device_debug(ec_device_t *ecd)
|
||||
void ec_device_print(ec_device_t *ecd)
|
||||
{
|
||||
printk(KERN_DEBUG "---EtherCAT device information begin---\n");
|
||||
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");
|
||||
}
|
||||
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");
|
||||
printk(KERN_DEBUG "---EtherCAT device information end---\n");
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
|
@ -336,36 +283,24 @@ void ec_device_debug(ec_device_t *ecd)
|
|||
|
||||
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;
|
||||
return ecd && ecd->dev == dev;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int EtherCAT_dev_receive(ec_device_t *ecd, void *data, unsigned int size)
|
||||
void 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;
|
||||
// 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 @@ EXPORT_SYMBOL(EtherCAT_dev_receive);
|
|||
|
||||
/* Emacs-Konfiguration
|
||||
;;; Local Variables: ***
|
||||
;;; c-basic-offset:2 ***
|
||||
;;; c-basic-offset:4 ***
|
||||
;;; End: ***
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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 @@ 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 *);
|
||||
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: ***
|
||||
*/
|
||||
|
|
|
|||
338
master/domain.c
338
master/domain.c
|
|
@ -8,33 +8,349 @@
|
|||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#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)
|
||||
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 */
|
||||
)
|
||||
{
|
||||
dom->number = -1;
|
||||
dom->data_size = 0;
|
||||
dom->logical_offset = 0;
|
||||
dom->response_count = 0xFFFFFFFF;
|
||||
domain->master = master;
|
||||
domain->mode = mode;
|
||||
domain->timeout_us = timeout_us;
|
||||
|
||||
memset(dom->data, 0x00, EC_FRAME_SIZE);
|
||||
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: ***
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -11,9 +11,27 @@
|
|||
#ifndef _EC_DOMAIN_H_
|
||||
#define _EC_DOMAIN_H_
|
||||
|
||||
#include <linux/list.h>
|
||||
|
||||
#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: ***
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,494 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* f r a m e . c
|
||||
*
|
||||
* Methoden für einen EtherCAT-Frame.
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#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: ***
|
||||
*/
|
||||
|
|
@ -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: ***
|
||||
*/
|
||||
|
|
@ -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: ***
|
||||
*/
|
||||
|
|
|
|||
1454
master/master.c
1454
master/master.c
File diff suppressed because it is too large
Load Diff
|
|
@ -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 @@ void ec_master_close(ec_master_t *);
|
|||
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 @@ int ec_simple_send_receive(ec_master_t *, ec_command_t *);
|
|||
|
||||
/* Emacs-Konfiguration
|
||||
;;; Local Variables: ***
|
||||
;;; c-basic-offset:2 ***
|
||||
;;; c-basic-offset:4 ***
|
||||
;;; End: ***
|
||||
*/
|
||||
|
|
|
|||
275
master/module.c
275
master/module.c
|
|
@ -69,46 +69,45 @@ MODULE_PARM_DESC(ec_master_count, "Number of EtherCAT master to initialize.");
|
|||
|
||||
int __init ec_init_module(void)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int i;
|
||||
|
||||
printk(KERN_ERR "EtherCAT: Master driver, %s\n", COMPILE_INFO);
|
||||
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;
|
||||
}
|
||||
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);
|
||||
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 =
|
||||
(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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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");
|
||||
printk(KERN_ERR "EtherCAT: Master driver initialized.\n");
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -121,26 +120,22 @@ int __init ec_init_module(void)
|
|||
|
||||
void __exit ec_cleanup_module(void)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int i;
|
||||
|
||||
printk(KERN_ERR "EtherCAT: Cleaning up master driver...\n");
|
||||
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]);
|
||||
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);
|
||||
}
|
||||
|
||||
kfree(ec_masters);
|
||||
}
|
||||
|
||||
printk(KERN_ERR "EtherCAT: Master driver cleaned up.\n");
|
||||
printk(KERN_ERR "EtherCAT: Master driver cleaned up.\n");
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
|
@ -158,8 +153,8 @@ void __exit ec_cleanup_module(void)
|
|||
@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 @@ ec_device_t *EtherCAT_dev_register(unsigned int master_index,
|
|||
struct pt_regs *),
|
||||
struct module *module)
|
||||
{
|
||||
ec_device_t *ecd;
|
||||
ec_master_t *master;
|
||||
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 (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;
|
||||
}
|
||||
if (!dev) {
|
||||
printk("EtherCAT: Device is NULL!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
master = ec_masters + master_index;
|
||||
master = ec_masters + master_index;
|
||||
|
||||
if (master->device_registered) {
|
||||
printk(KERN_ERR "EtherCAT: Master %i already has a device!\n",
|
||||
master_index);
|
||||
return NULL;
|
||||
}
|
||||
if (master->device_registered) {
|
||||
printk(KERN_ERR "EtherCAT: Master %i already has a device!\n",
|
||||
master_index);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ecd = &master->device;
|
||||
ecd = &master->device;
|
||||
|
||||
if (ec_device_init(ecd) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
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;
|
||||
ecd->dev = dev;
|
||||
ecd->tx_skb->dev = dev;
|
||||
ecd->isr = isr;
|
||||
ecd->module = module;
|
||||
|
||||
master->device_registered = 1;
|
||||
master->device_registered = 1;
|
||||
|
||||
return ecd;
|
||||
return ecd;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -217,22 +209,23 @@ ec_device_t *EtherCAT_dev_register(unsigned int master_index,
|
|||
|
||||
void EtherCAT_dev_unregister(unsigned int master_index, ec_device_t *ecd)
|
||||
{
|
||||
ec_master_t *master;
|
||||
ec_master_t *master;
|
||||
|
||||
if (master_index >= ec_master_count) {
|
||||
printk(KERN_WARNING "EtherCAT: Master %i does not exist!\n", master_index);
|
||||
return;
|
||||
}
|
||||
if (master_index >= ec_master_count) {
|
||||
printk(KERN_WARNING "EtherCAT: Master %i does not exist!\n",
|
||||
master_index);
|
||||
return;
|
||||
}
|
||||
|
||||
master = ec_masters + master_index;
|
||||
master = ec_masters + master_index;
|
||||
|
||||
if (!master->device_registered || &master->device != ecd) {
|
||||
printk(KERN_ERR "EtherCAT: Unable to unregister device!\n");
|
||||
return;
|
||||
}
|
||||
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);
|
||||
master->device_registered = 0;
|
||||
ec_device_clear(ecd);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
|
@ -252,54 +245,54 @@ void EtherCAT_dev_unregister(unsigned int master_index, ec_device_t *ecd)
|
|||
|
||||
ec_master_t *EtherCAT_rt_request_master(unsigned int index)
|
||||
{
|
||||
ec_master_t *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 (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;
|
||||
}
|
||||
if (ec_masters_reserved[index]) {
|
||||
printk(KERN_ERR "EtherCAT: Master %i already in use!\n", index);
|
||||
goto req_return;
|
||||
}
|
||||
|
||||
master = &ec_masters[index];
|
||||
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 (!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 (!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: Could not open device!\n");
|
||||
goto req_module_put;
|
||||
}
|
||||
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: Could not scan for slaves!\n");
|
||||
goto req_close;
|
||||
}
|
||||
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);
|
||||
ec_masters_reserved[index] = 1;
|
||||
printk(KERN_INFO "EtherCAT: Reserved master %i.\n", index);
|
||||
|
||||
return master;
|
||||
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 @@ ec_master_t *EtherCAT_rt_request_master(unsigned int index)
|
|||
|
||||
void EtherCAT_rt_release_master(ec_master_t *master)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ec_master_count; i++)
|
||||
{
|
||||
if (&ec_masters[i] == master)
|
||||
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;
|
||||
}
|
||||
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);
|
||||
ec_master_close(master);
|
||||
ec_master_reset(master);
|
||||
|
||||
module_put(master->device.module);
|
||||
ec_masters_reserved[i] = 0;
|
||||
module_put(master->device.module);
|
||||
ec_masters_reserved[i] = 0;
|
||||
|
||||
printk(KERN_INFO "EtherCAT: Released master %i.\n", i);
|
||||
printk(KERN_INFO "EtherCAT: Released master %i.\n", i);
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printk(KERN_WARNING "EtherCAT: Master %X was never requested!\n",
|
||||
(unsigned int) master);
|
||||
printk(KERN_WARNING "EtherCAT: Master %X was never requested!\n",
|
||||
(unsigned int) master);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -354,6 +347,6 @@ EXPORT_SYMBOL(EtherCAT_rt_release_master);
|
|||
|
||||
/* Emacs-Konfiguration
|
||||
;;; Local Variables: ***
|
||||
;;; c-basic-offset:2 ***
|
||||
;;; c-basic-offset:4 ***
|
||||
;;; End: ***
|
||||
*/
|
||||
|
|
|
|||
435
master/slave.c
435
master/slave.c
|
|
@ -9,48 +9,431 @@
|
|||
*****************************************************************************/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#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)
|
||||
void ec_slave_init(ec_slave_t *slave, /**< EtherCAT-Slave */
|
||||
ec_master_t *master /**< EtherCAT-Master */
|
||||
)
|
||||
{
|
||||
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;
|
||||
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: ***
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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 @@ void ec_slave_init(ec_slave_t *);
|
|||
|
||||
/* Emacs-Konfiguration
|
||||
;;; Local Variables: ***
|
||||
;;; c-basic-offset:2 ***
|
||||
;;; c-basic-offset:4 ***
|
||||
;;; End: ***
|
||||
*/
|
||||
|
|
|
|||
230
master/types.c
230
master/types.c
|
|
@ -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 @@ ec_slave_ident_t slave_idents[] =
|
|||
{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: ***
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -11,10 +11,17 @@
|
|||
#ifndef _EC_TYPES_H_
|
||||
#define _EC_TYPES_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "../include/EtherCAT_rt.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#define EC_MAX_FIELDS 10
|
||||
#define EC_MAX_SYNC 16
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Features eines EtherCAT-Slaves.
|
||||
|
||||
|
|
@ -31,6 +38,34 @@ ec_slave_features_t;
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
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.
|
||||
|
||||
|
|
@ -39,28 +74,16 @@ ec_slave_features_t;
|
|||
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 @@ ec_slave_ident_t;
|
|||
|
||||
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: ***
|
||||
*/
|
||||
|
|
|
|||
98
mini/mini.c
98
mini/mini.c
|
|
@ -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 }
|
||||
};
|
||||
/*****************************************************************************/
|
||||
|
||||
#define SLAVE_COUNT (sizeof(slaves) / sizeof(ec_slave_init_t))
|
||||
// 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},
|
||||
{}
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
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 @@ void run(unsigned long data)
|
|||
|
||||
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 @@ void __exit cleanup_mini_module(void)
|
|||
{
|
||||
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 @@ void __exit cleanup_mini_module(void)
|
|||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR ("Florian Pose <fp@igh-essen.com>");
|
||||
MODULE_DESCRIPTION ("Minimal EtherCAT environment");
|
||||
MODULE_DESCRIPTION ("EtherCAT minimal test environment");
|
||||
|
||||
module_init(init_mini_module);
|
||||
module_exit(cleanup_mini_module);
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ ifneq ($(KERNELRELEASE),)
|
|||
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 @@ msr_modul-objs := msr_module.o \
|
|||
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 \
|
||||
|
|
|
|||
129
rt/msr_jitter.c
129
rt/msr_jitter.c
|
|
@ -1,129 +0,0 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* msr_jitter.c
|
||||
*
|
||||
* Autor: Wilhelm Hagemeister
|
||||
*
|
||||
* (C) Copyright IgH 2002
|
||||
* Ingenieurgemeinschaft IgH
|
||||
* Heinz-B<EFBFBD>ä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 <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/msr.h> /* maschine-specific registers */
|
||||
#include <linux/param.h> /* fuer HZ */
|
||||
|
||||
#include <msr_reg.h>
|
||||
#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;i<NUMCLASSES;i++) {
|
||||
if(tcount >100) {
|
||||
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<EFBFBD>ü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<NUMCLASSES-1;i++) {
|
||||
if(jitter>=jittime[i] && jitter<jittime[i+1]) {
|
||||
jitcount[i]++;
|
||||
hit = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(hit == 0) //grŽöŽßer als der letzte
|
||||
jitcount[NUMCLASSES-1]++;
|
||||
|
||||
}
|
||||
else
|
||||
firstrun = 0;
|
||||
|
||||
j = k;
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,27 +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$
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*--Schutz vor mehrfachem includieren----------------------------------------*/
|
||||
|
||||
#ifndef _MSR_JITTER_H_
|
||||
#define _MSR_JITTER_H_
|
||||
|
||||
void msr_jitter_run(unsigned int hz);
|
||||
void msr_jitter_init(void);
|
||||
|
||||
#endif
|
||||
166
rt/msr_module.c
166
rt/msr_module.c
|
|
@ -21,6 +21,8 @@
|
|||
// Linux
|
||||
#include <linux/module.h>
|
||||
#include <linux/ipipe.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
// RT_lib
|
||||
#include <msr_main.h>
|
||||
|
|
@ -28,105 +30,62 @@
|
|||
#include <msr_messages.h>
|
||||
#include <msr_float.h>
|
||||
#include <msr_reg.h>
|
||||
#include <msr_time.h>
|
||||
#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;
|
||||
ec_domain_t *domain1 = NULL;
|
||||
|
||||
uint16_t angle0;
|
||||
// Prozessdaten
|
||||
uint8_t *dig_out1;
|
||||
uint16_t *ssi_value;
|
||||
uint16_t *inc_value;
|
||||
|
||||
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}
|
||||
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);
|
||||
EtherCAT_rt_domain_xio(domain1);
|
||||
|
||||
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);
|
||||
angle0 = (uint32_t) *inc_value;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Function: msr_run(_interrupt)
|
||||
*
|
||||
* Beschreibung: Routine wird zyklisch im Timerinterrupt ausgef<EFBFBD>ührt
|
||||
* (hier mu<EFBFBD>ß alles rein, was Echtzeit ist ...)
|
||||
*
|
||||
* Parameter: Zeiger auf msr_data
|
||||
*
|
||||
* R<EFBFBD>ückgabe:
|
||||
*
|
||||
* Status: exp
|
||||
*
|
||||
*****************************************************************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
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 @@ void domain_entry(void)
|
|||
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");
|
||||
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;
|
||||
}
|
||||
|
||||
if (EtherCAT_rt_activate_slaves(master) < 0) {
|
||||
printk(KERN_ERR "EtherCAT: Could not activate slaves!\n");
|
||||
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 (EtherCAT_rt_canopen_sdo_write(master, s_ssi, 0x4067, 0, 1, 2)) {
|
||||
#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 @@ void __exit cleanup_rt_module(void)
|
|||
{
|
||||
printk(KERN_INFO "=== Stopping EtherCAT environment... ===\n");
|
||||
|
||||
printk(KERN_INFO "Deactivating slaves.\n");
|
||||
printk(KERN_INFO "Deactivating master...\n");
|
||||
|
||||
if (EtherCAT_rt_deactivate_slaves(master) < 0) {
|
||||
printk(KERN_WARNING "Warning - Could not deactivate slaves!\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 @@ void __exit cleanup_rt_module(void)
|
|||
/*****************************************************************************/
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR ("Wilhelm Hagemeister <hm@igh-essen.com>");
|
||||
MODULE_DESCRIPTION ("EtherCAT test environment");
|
||||
MODULE_AUTHOR ("Florian Pose <fp@igh-essen.com>");
|
||||
MODULE_DESCRIPTION ("EtherCAT real-time test environment");
|
||||
|
||||
module_init(init_rt_module);
|
||||
module_exit(cleanup_rt_module);
|
||||
|
|
|
|||
Loading…
Reference in New Issue