mirror of
https://gitlab.com/etherlab.org/ethercat.git
synced 2026-08-18 09:07:24 +08:00
Implemented most realtime interface changes for version 1.4, improved
ec_pdo_t and ec_pdo_entry_t classes, added fmmu_config_t, adjusted minimal example, etc...
This commit is contained in:
@@ -6,6 +6,40 @@ $Id$
|
||||
|
||||
Changes in version 1.4.0:
|
||||
|
||||
* Realtime interface changes:
|
||||
- Replaced ec_slave_t with ec_slave_config_t, separating the slave objects
|
||||
from the requested bus configuration. Therefore, renamed
|
||||
ecrt_master_get_slave() to ecrt_master_slave_config().
|
||||
- Replaced slave address string with alias and position values. See
|
||||
ecrt_master_slave_config().
|
||||
- Removed ecrt_master_get_slave_by_pos(), because it is no longer
|
||||
necessary (alias/position, slave configurations).
|
||||
- Added ec_slave_config_state_t for the new method
|
||||
ecrt_slave_config_state().
|
||||
- Process data memory for a domain can now be allocated externally. This
|
||||
offers the possibility to use a shared-memory-region. Therefore,
|
||||
added the domain methods ecrt_domain_size() and ecrt_domain_memory().
|
||||
- Replaced the process data pointers in the Pdo entry registration
|
||||
functions with a process data offset, that is now returned by
|
||||
ecrt_domain_reg_pdo_entry(). This was necessary for the external
|
||||
domain memory. An additional advantage is, that the returned offset value
|
||||
is directly usable.
|
||||
- Replaced ecrt_slave_pdo_mapping/add/clear() with
|
||||
ecrt_slave_config_mapping() that is now able to specify Pdo mapping and
|
||||
Pdo configuration. Pdo entries mapped in this way can now immediately be
|
||||
registered. The Pdo mapping and the configuration are described with the
|
||||
new data types ec_pdo_info_t and ec_pdo_entry_info_t.
|
||||
- Renamed ec_bus_status_t, ec_master_status_t to ec_bus_state_t and
|
||||
ec_master_state_t, respectively. Renamed ecrt_master_get_status() to
|
||||
ecrt_master_state(), for consistency reasons.
|
||||
- Added ec_domain_state_t and ec_wc_state_t for a new output parameter
|
||||
of ecrt_domain_state().
|
||||
- Former "Pdo registration" meant Pdo entry registration in fact, therefore
|
||||
renamed ec_pdo_reg_t to ec_pdo_entry_reg_t and ecrt_domain_register_pdo()
|
||||
to ecrt_domain_reg_pdo_entry().
|
||||
- Removed ecrt_domain_register_pdo_range(), because it's functionality can
|
||||
be reached by specifying an explicit Pdo mapping and registering those
|
||||
Pdo entries.
|
||||
* Added 8139too driver for kernel 2.6.22, thanks to Erwin Burgstaller.
|
||||
* Added e1000 driver for kernel 2.6.22.
|
||||
* Allow gaps in PDO mapping read from CoE.
|
||||
|
||||
@@ -11,9 +11,7 @@ Version 1.4.0:
|
||||
* Realtime interface changes:
|
||||
- PDO configuration.
|
||||
- SDO access.
|
||||
- Replace process data pointers with offset.
|
||||
- External memory for domains.
|
||||
- Separate slave configuration from slave structure.
|
||||
* Mailbox handler
|
||||
* Read PDO mapping via CoE during bus scan.
|
||||
* SDO write access in sysfs.
|
||||
@@ -22,6 +20,11 @@ Version 1.4.0:
|
||||
* Remove ecdb.h and let lsec output PDO information 'cut-and-pastable' for
|
||||
applications.
|
||||
* Update documentation.
|
||||
* READMEs for examples.
|
||||
* Calculate expected working counter for domains.
|
||||
* Distributed clocks.
|
||||
* Support slaves, that don't support the LRW datagram, only LRD/LWR.
|
||||
* Implement all EtherCAT datagram types.
|
||||
|
||||
Future issues:
|
||||
|
||||
@@ -30,10 +33,7 @@ Future issues:
|
||||
to replace lsec.
|
||||
- Step 2: Move kernel threads to user space daemon with a TCP interface
|
||||
replacing the cdev.
|
||||
* Distributed clocks.
|
||||
* Redundancy with 2 network adapters.
|
||||
* Support slaves, that don't support the LRW datagram, only LRD/LWR.
|
||||
* PDO reading in IDLE mode.
|
||||
* Interface/buffers for asynchronous domain IO.
|
||||
|
||||
Smaller issues:
|
||||
@@ -42,12 +42,9 @@ Smaller issues:
|
||||
* Clear sync managers in INIT.
|
||||
* Simplify FSMs with <state>_enter() functions.
|
||||
* Read out CRC counters.
|
||||
* Calculate expected working counter for domains.
|
||||
* Optimize alignment of process data.
|
||||
* Evaluate EEPROM contents after writing.
|
||||
* Configure slave ports to automatically open on link detection.
|
||||
* Calculate cycle time of operation state machine.
|
||||
* Locking for serveral slave variables for sysfs access.
|
||||
* Interrupt master state machines state scan for other jobs.
|
||||
* Master state machine, slave configuration: Do not check every slave on
|
||||
a cycle.
|
||||
@@ -55,7 +52,6 @@ Smaller issues:
|
||||
|
||||
Less important issues:
|
||||
|
||||
* Implement all EtherCAT datagram types.
|
||||
* File access over EtherCAT (FoE).
|
||||
* Allow VLAN tagging.
|
||||
* Determine number of frames, the NIC can handle.
|
||||
|
||||
@@ -8,6 +8,7 @@ digraph slaveconf {
|
||||
enter_sdoconf [shape=point,label=""]
|
||||
enter_mapconf [shape=point,label=""]
|
||||
enter_pdo_sync [shape=point,label=""]
|
||||
enter_saveop [shape=point,label=""]
|
||||
|
||||
start -> init [weight=10]
|
||||
init -> init
|
||||
@@ -18,8 +19,8 @@ digraph slaveconf {
|
||||
clear_fmmus -> error
|
||||
clear_fmmus -> enter_mbox_sync [weight=10]
|
||||
enter_mbox_sync -> end [label="INIT req."]
|
||||
enter_mbox_sync -> preop
|
||||
enter_mbox_sync -> mbox_sync [label="mailbox SMs", weight=10]
|
||||
enter_mbox_sync -> preop [label="No mailboxes"]
|
||||
enter_mbox_sync -> mbox_sync [label="Has mailboxes", weight=10]
|
||||
mbox_sync -> mbox_sync
|
||||
mbox_sync -> error
|
||||
mbox_sync -> preop [weight=10]
|
||||
@@ -27,8 +28,9 @@ digraph slaveconf {
|
||||
preop -> error
|
||||
preop -> end [label="PREOP req."]
|
||||
preop -> enter_sdoconf [weight=10]
|
||||
enter_sdoconf -> enter_mapconf
|
||||
enter_sdoconf -> sdoconf [label="SDOs to configure", weight=10]
|
||||
enter_sdoconf -> enter_saveop [label="No configuration"]
|
||||
enter_sdoconf -> enter_mapconf [label="No SDO configs"]
|
||||
enter_sdoconf -> sdoconf [label="SDO configs", weight=10]
|
||||
sdoconf -> sdoconf
|
||||
sdoconf -> error
|
||||
sdoconf -> enter_mapconf [weight=10]
|
||||
@@ -42,11 +44,12 @@ digraph slaveconf {
|
||||
pdo_sync -> pdo_sync
|
||||
pdo_sync -> error
|
||||
pdo_sync -> enter_fmmu [weight=10]
|
||||
enter_fmmu -> saveop
|
||||
enter_fmmu -> enter_saveop
|
||||
enter_fmmu -> fmmu [label="FMMUs to configure", weight=10]
|
||||
fmmu -> fmmu
|
||||
fmmu -> error
|
||||
fmmu -> saveop [weight=10]
|
||||
fmmu -> enter_saveop [weight=10]
|
||||
enter_saveop -> saveop
|
||||
saveop -> saveop
|
||||
saveop -> error
|
||||
saveop -> end [label="SAVEOP req."]
|
||||
|
||||
+41
-60
@@ -44,6 +44,8 @@
|
||||
#define FREQUENCY 100
|
||||
|
||||
//#define KBUS
|
||||
#define PDOS
|
||||
#define MAPPING
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@@ -53,7 +55,7 @@ static struct timer_list timer;
|
||||
static ec_master_t *master = NULL;
|
||||
static ec_domain_t *domain1 = NULL;
|
||||
spinlock_t master_lock = SPIN_LOCK_UNLOCKED;
|
||||
static ec_master_status_t master_status, old_status = {};
|
||||
static ec_master_state_t master_state, old_state = {};
|
||||
|
||||
// data fields
|
||||
#ifdef KBUS
|
||||
@@ -61,17 +63,20 @@ static void *r_inputs;
|
||||
static void *r_outputs;
|
||||
#endif
|
||||
|
||||
static void *r_dig_out;
|
||||
static void *r_ana_out;
|
||||
static void *r_count;
|
||||
static void *r_freq;
|
||||
#ifdef MAPPING
|
||||
const ec_pdo_info_t mapping[] = {
|
||||
{EC_DIR_INPUT, 0x1A00}, // channel 1
|
||||
{EC_DIR_INPUT, 0x1A01} // channel 2
|
||||
};
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
const static ec_pdo_reg_t domain1_pdo_regs[] = {
|
||||
{"2", Beckhoff_EL2004_Outputs, &r_dig_out},
|
||||
{"3", Beckhoff_EL4132_Output1, &r_ana_out},
|
||||
{"#888:1", Beckhoff_EL5101_Value, &r_count},
|
||||
{"4", Beckhoff_EL5101_Frequency, &r_freq},
|
||||
#ifdef PDOS
|
||||
static uint8_t off_ana_in;
|
||||
static uint8_t off_ana_out;
|
||||
|
||||
const static ec_pdo_entry_reg_t domain1_regs[] = {
|
||||
{0, 1, Beckhoff_EL3162, 0x3101, 2, &off_ana_in},
|
||||
{0, 2, Beckhoff_EL4102, 0x3001, 1, &off_ana_out},
|
||||
{}
|
||||
};
|
||||
#endif
|
||||
@@ -91,7 +96,7 @@ void run(unsigned long data)
|
||||
|
||||
// process data
|
||||
// k_pos = EC_READ_U32(r_ssi);
|
||||
EC_WRITE_U8(r_dig_out, blink ? 0x0F : 0x00);
|
||||
//EC_WRITE_U8(r_dig_out, blink ? 0x0F : 0x00);
|
||||
|
||||
if (counter) {
|
||||
counter--;
|
||||
@@ -101,24 +106,24 @@ void run(unsigned long data)
|
||||
blink = !blink;
|
||||
|
||||
spin_lock(&master_lock);
|
||||
ecrt_master_get_status(master, &master_status);
|
||||
ecrt_master_state(master, &master_state);
|
||||
spin_unlock(&master_lock);
|
||||
|
||||
if (master_status.bus_status != old_status.bus_status) {
|
||||
printk(KERN_INFO PFX "bus status changed to %i.\n",
|
||||
master_status.bus_status);
|
||||
if (master_state.bus_state != old_state.bus_state) {
|
||||
printk(KERN_INFO PFX "bus state changed to %i.\n",
|
||||
master_state.bus_state);
|
||||
}
|
||||
if (master_status.bus_tainted != old_status.bus_tainted) {
|
||||
if (master_state.bus_tainted != old_state.bus_tainted) {
|
||||
printk(KERN_INFO PFX "tainted flag changed to %u.\n",
|
||||
master_status.bus_tainted);
|
||||
master_state.bus_tainted);
|
||||
}
|
||||
if (master_status.slaves_responding !=
|
||||
old_status.slaves_responding) {
|
||||
if (master_state.slaves_responding !=
|
||||
old_state.slaves_responding) {
|
||||
printk(KERN_INFO PFX "slaves_responding changed to %u.\n",
|
||||
master_status.slaves_responding);
|
||||
master_state.slaves_responding);
|
||||
}
|
||||
|
||||
old_status = master_status;
|
||||
old_state = master_state;
|
||||
}
|
||||
|
||||
#ifdef KBUS
|
||||
@@ -158,10 +163,10 @@ void release_lock(void *data)
|
||||
|
||||
int __init init_mini_module(void)
|
||||
{
|
||||
#if 1
|
||||
ec_slave_t *slave;
|
||||
#ifdef MAPPING
|
||||
ec_slave_config_t *sc;
|
||||
#endif
|
||||
|
||||
|
||||
printk(KERN_INFO PFX "Starting...\n");
|
||||
|
||||
if (!(master = ecrt_request_master(0))) {
|
||||
@@ -177,49 +182,25 @@ int __init init_mini_module(void)
|
||||
goto out_release_master;
|
||||
}
|
||||
|
||||
#if 1
|
||||
printk(KERN_INFO PFX "Configuring alternative PDO mapping...\n");
|
||||
if (!(slave = ecrt_master_get_slave(master, "4", Beckhoff_EL5101)))
|
||||
#ifdef MAPPING
|
||||
printk(KERN_INFO PFX "Configuring Pdo mapping...\n");
|
||||
if (!(sc = ecrt_master_slave_config(master, 0, 1, Beckhoff_EL3162))) {
|
||||
printk(KERN_ERR PFX "Failed to get slave configuration.\n");
|
||||
goto out_release_master;
|
||||
}
|
||||
|
||||
if (ecrt_slave_pdo_mapping(slave, EC_DIR_INPUT, 2, 0x1A00, 0x1A02))
|
||||
goto out_release_master;
|
||||
#endif
|
||||
|
||||
printk(KERN_INFO PFX "Registering PDOs...\n");
|
||||
#if 1
|
||||
if (ecrt_domain_register_pdo_list(domain1, domain1_pdo_regs)) {
|
||||
printk(KERN_ERR PFX "PDO registration failed!\n");
|
||||
if (ecrt_slave_config_mapping(sc, 2, mapping)) {
|
||||
printk(KERN_ERR PFX "Failed to configure Pdo mapping.\n");
|
||||
goto out_release_master;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef KBUS
|
||||
if (!(slave = ecrt_master_get_slave(master, "0", Beckhoff_BK1120)))
|
||||
goto out_release_master;
|
||||
|
||||
if (!ecrt_domain_register_pdo_range(
|
||||
domain1, slave, EC_DIR_OUTPUT, 0, 4, &r_outputs)) {
|
||||
printk(KERN_ERR PFX "PDO registration failed!\n");
|
||||
printk(KERN_INFO PFX "Registering PDO entries...\n");
|
||||
#ifdef PDOS
|
||||
if (ecrt_domain_reg_pdo_entry_list(domain1, domain1_regs)) {
|
||||
printk(KERN_ERR PFX "PDO entry registration failed!\n");
|
||||
goto out_release_master;
|
||||
}
|
||||
|
||||
if (!ecrt_domain_register_pdo_range(
|
||||
domain1, slave, EC_DIR_INPUT, 0, 4, &r_inputs)) {
|
||||
printk(KERN_ERR PFX "PDO registration failed!\n");
|
||||
goto out_release_master;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
if (!(slave = ecrt_master_get_slave(master, "4", Beckhoff_EL5001)))
|
||||
goto out_release_master;
|
||||
|
||||
if (ecrt_slave_conf_sdo8(slave, 0x4061, 1, 0))
|
||||
goto out_release_master;
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
#endif
|
||||
|
||||
printk(KERN_INFO PFX "Activating master...\n");
|
||||
|
||||
+407
-72
File diff suppressed because it is too large
Load Diff
+4
-3
@@ -33,9 +33,10 @@
|
||||
|
||||
obj-m := ec_master.o
|
||||
|
||||
ec_master-objs := module.o master.o device.o pdo.o sync.o fmmu.o slave.o \
|
||||
datagram.o domain.o mailbox.o canopen.o fsm_sii.o fsm_change.o \
|
||||
fsm_coe.o fsm_coe_map.o fsm_mapping.o fsm_slave.o fsm_master.o xmldev.o
|
||||
ec_master-objs := module.o master.o device.o pdo.o sync.o fmmu_config.o \
|
||||
slave.o slave_config.o pdo_mapping.o datagram.o domain.o mailbox.o \
|
||||
canopen.o fsm_sii.o fsm_change.o fsm_coe.o fsm_coe_map.o fsm_mapping.o \
|
||||
fsm_slave.o fsm_master.o xmldev.o
|
||||
|
||||
ifeq (@ENABLE_EOE@,1)
|
||||
ec_master-objs += ethernet.o
|
||||
|
||||
+3
-1
@@ -39,7 +39,7 @@ EXTRA_DIST = \
|
||||
device.c device.h \
|
||||
pdo.c pdo.h \
|
||||
sync.c sync.h \
|
||||
fmmu.c fmmu.h \
|
||||
fmmu_config.c fmmu_config.h \
|
||||
domain.c domain.h \
|
||||
doxygen.c \
|
||||
ethernet.c ethernet.h \
|
||||
@@ -55,6 +55,8 @@ EXTRA_DIST = \
|
||||
master.c master.h \
|
||||
module.c \
|
||||
slave.c slave.h \
|
||||
slave_config.c slave_config.h \
|
||||
pdo_mapping.c pdo_mapping.h \
|
||||
xmldev.c xmldev.h
|
||||
|
||||
modules:
|
||||
|
||||
+84
-318
File diff suppressed because it is too large
Load Diff
+13
-14
@@ -58,19 +58,18 @@
|
||||
|
||||
struct ec_domain
|
||||
{
|
||||
struct kobject kobj; /**< kobject */
|
||||
struct list_head list; /**< list item */
|
||||
unsigned int index; /**< domain index (just a number) */
|
||||
ec_master_t *master; /**< EtherCAT master owning the domain */
|
||||
size_t data_size; /**< size of the process data */
|
||||
struct list_head datagrams; /**< process data datagrams */
|
||||
uint32_t base_address; /**< logical offset address of the process data */
|
||||
unsigned int response_count; /**< number of responding slaves */
|
||||
unsigned int state; /**< domain error state */
|
||||
struct list_head data_regs; /**< PDO data registrations */
|
||||
unsigned int working_counter_changes; /**< working counter changes
|
||||
since last notification */
|
||||
unsigned long notify_jiffies; /**< time of last notification */
|
||||
struct kobject kobj; /**< kobject. */
|
||||
struct list_head list; /**< List item. */
|
||||
unsigned int index; /**< Index (just a number). */
|
||||
ec_master_t *master; /**< EtherCAT master owning the domain. */
|
||||
size_t data_size; /**< Size of the process data. */
|
||||
struct list_head datagrams; /**< Datagrams for process data exchange. */
|
||||
uint32_t base_address; /**< Logical offset address of the process data. */
|
||||
unsigned int working_counter; /**< Last working counter value. */
|
||||
unsigned int state; /**< Error state. */
|
||||
unsigned int working_counter_changes; /**< Working counter changes
|
||||
since last notification. */
|
||||
unsigned long notify_jiffies; /**< Time of last notification. */
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -78,7 +77,7 @@ struct ec_domain
|
||||
int ec_domain_init(ec_domain_t *, ec_master_t *, unsigned int);
|
||||
void ec_domain_destroy(ec_domain_t *);
|
||||
|
||||
int ec_domain_alloc(ec_domain_t *, uint32_t);
|
||||
int ec_domain_finish(ec_domain_t *, uint32_t);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
@@ -31,63 +31,68 @@
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
\file
|
||||
EtherCAT FMMU methods.
|
||||
*/
|
||||
/** \file
|
||||
* EtherCAT FMMU configuration methods.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#include "globals.h"
|
||||
#include "slave.h"
|
||||
#include "slave_config.h"
|
||||
#include "master.h"
|
||||
#include "fmmu.h"
|
||||
|
||||
#include "fmmu_config.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* FMMU Constructor.
|
||||
/** FMMU configuration constructor.
|
||||
*
|
||||
* Inits an FMMU configuration, sets the logical start address and adds the
|
||||
* process data size for the mapped PDOs of the given direction to the domain
|
||||
* data size.
|
||||
*/
|
||||
|
||||
void ec_fmmu_init(
|
||||
ec_fmmu_t *fmmu, /**< EtherCAT FMMU */
|
||||
ec_slave_t *slave, /**< EtherCAT slave */
|
||||
unsigned int index /**< FMMU index */
|
||||
void ec_fmmu_config_init(
|
||||
ec_fmmu_config_t *fmmu, /**< EtherCAT FMMU configuration. */
|
||||
ec_slave_config_t *sc, /**< EtherCAT slave configuration. */
|
||||
ec_domain_t *domain, /**< EtherCAT domain. */
|
||||
ec_direction_t dir /**< PDO direction. */
|
||||
)
|
||||
{
|
||||
fmmu->slave = slave;
|
||||
fmmu->index = index;
|
||||
fmmu->sc = sc;
|
||||
fmmu->domain = domain;
|
||||
fmmu->dir = dir;
|
||||
|
||||
fmmu->logical_start_address = domain->data_size;
|
||||
fmmu->data_size = ec_pdo_mapping_total_size(&sc->mapping[dir]);
|
||||
domain->data_size += fmmu->data_size;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Initializes an FMMU configuration page.
|
||||
* The referenced memory (\a data) must be at least EC_FMMU_SIZE bytes.
|
||||
/** Initializes an FMMU configuration page.
|
||||
*
|
||||
* The referenced memory (\a data) must be at least EC_FMMU_PAGE_SIZE bytes.
|
||||
*/
|
||||
|
||||
void ec_fmmu_config(
|
||||
const ec_fmmu_t *fmmu, /**< EtherCAT FMMU */
|
||||
uint8_t *data /**> configuration memory */
|
||||
void ec_fmmu_config_page(
|
||||
const ec_fmmu_config_t *fmmu, /**< EtherCAT FMMU configuration. */
|
||||
const ec_sync_t *sync, /**< Sync manager. */
|
||||
uint8_t *data /**> Configuration page memory. */
|
||||
)
|
||||
{
|
||||
size_t sync_size = ec_sync_size(fmmu->sync);
|
||||
|
||||
if (fmmu->slave->master->debug_level) {
|
||||
EC_DBG("FMMU%u: LogAddr 0x%08X, Size %3i, PhysAddr 0x%04X, Dir %s\n",
|
||||
fmmu->index, fmmu->logical_start_address,
|
||||
sync_size, fmmu->sync->physical_start_address,
|
||||
((fmmu->sync->control_register & 0x04) ? "out" : "in"));
|
||||
if (fmmu->sc->master->debug_level) {
|
||||
EC_DBG("FMMU: LogAddr 0x%08X, Size %3i, PhysAddr 0x%04X, Dir %s\n",
|
||||
fmmu->logical_start_address, fmmu->data_size,
|
||||
sync->physical_start_address,
|
||||
(sync->control_register & 0x04) ? "out" : "in");
|
||||
}
|
||||
|
||||
EC_WRITE_U32(data, fmmu->logical_start_address);
|
||||
EC_WRITE_U16(data + 4, sync_size); // size of fmmu
|
||||
EC_WRITE_U16(data + 4, fmmu->data_size); // size of fmmu
|
||||
EC_WRITE_U8 (data + 6, 0x00); // logical start bit
|
||||
EC_WRITE_U8 (data + 7, 0x07); // logical end bit
|
||||
EC_WRITE_U16(data + 8, fmmu->sync->physical_start_address);
|
||||
EC_WRITE_U16(data + 8, sync->physical_start_address);
|
||||
EC_WRITE_U8 (data + 10, 0x00); // physical start bit
|
||||
EC_WRITE_U8 (data + 11, ((fmmu->sync->control_register & 0x04)
|
||||
? 0x02 : 0x01));
|
||||
EC_WRITE_U8 (data + 11, (sync->control_register & 0x04) ? 0x02 : 0x01);
|
||||
EC_WRITE_U16(data + 12, 0x0001); // enable
|
||||
EC_WRITE_U16(data + 14, 0x0000); // reserved
|
||||
}
|
||||
@@ -31,15 +31,14 @@
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
\file
|
||||
EtherCAT FMMU structure.
|
||||
*/
|
||||
/** \file
|
||||
* EtherCAT FMMU configuration structure.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef _EC_FMMU_H_
|
||||
#define _EC_FMMU_H_
|
||||
#ifndef _EC_FMMU_CONFIG_H_
|
||||
#define _EC_FMMU_CONFIG_H_
|
||||
|
||||
#include "../include/ecrt.h"
|
||||
|
||||
@@ -47,30 +46,26 @@
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** size of an FMMU configuration page */
|
||||
#define EC_FMMU_SIZE 16
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* FMMU configuration.
|
||||
/** FMMU configuration.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const ec_slave_t *slave; /**< EtherCAT slave, the FMMU belongs to */
|
||||
unsigned int index; /**< FMMU index */
|
||||
const ec_domain_t *domain; /**< domain */
|
||||
const ec_sync_t *sync; /**< sync manager */
|
||||
uint32_t logical_start_address; /**< logical start address */
|
||||
const ec_slave_config_t *sc; /**< EtherCAT slave config. */
|
||||
const ec_domain_t *domain; /**< Domain. */
|
||||
ec_direction_t dir; /**< PDO direction. */
|
||||
|
||||
uint32_t logical_start_address; /**< Logical start address. */
|
||||
unsigned int data_size; /**< Covered PDO size. */
|
||||
}
|
||||
ec_fmmu_t;
|
||||
ec_fmmu_config_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_fmmu_init(ec_fmmu_t *, ec_slave_t *, unsigned int);
|
||||
void ec_fmmu_config_init(ec_fmmu_config_t *, ec_slave_config_t *,
|
||||
ec_domain_t *, ec_direction_t);
|
||||
|
||||
void ec_fmmu_config(const ec_fmmu_t *, uint8_t *);
|
||||
void ec_fmmu_config_page(const ec_fmmu_config_t *, const ec_sync_t *,
|
||||
uint8_t *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
+28
-66
@@ -59,8 +59,6 @@ void ec_fsm_coe_map_action_next_sync(ec_fsm_coe_map_t *);
|
||||
void ec_fsm_coe_map_action_next_pdo(ec_fsm_coe_map_t *);
|
||||
void ec_fsm_coe_map_action_next_pdo_entry(ec_fsm_coe_map_t *);
|
||||
|
||||
void ec_fsm_coe_map_clear_pdos(ec_fsm_coe_map_t *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
@@ -74,7 +72,7 @@ void ec_fsm_coe_map_init(
|
||||
{
|
||||
fsm->state = NULL;
|
||||
fsm->fsm_coe = fsm_coe;
|
||||
INIT_LIST_HEAD(&fsm->pdos);
|
||||
ec_pdo_mapping_init(&fsm->mapping);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -85,27 +83,7 @@ void ec_fsm_coe_map_init(
|
||||
|
||||
void ec_fsm_coe_map_clear(ec_fsm_coe_map_t *fsm /**< finite state machine */)
|
||||
{
|
||||
ec_fsm_coe_map_clear_pdos(fsm);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Clear FSM PDOs.
|
||||
*/
|
||||
|
||||
void ec_fsm_coe_map_clear_pdos(
|
||||
ec_fsm_coe_map_t *fsm /**< finite state machine */
|
||||
)
|
||||
{
|
||||
ec_pdo_t *pdo, *next;
|
||||
|
||||
// free all PDOs
|
||||
list_for_each_entry_safe(pdo, next, &fsm->pdos, list) {
|
||||
list_del(&pdo->list);
|
||||
ec_pdo_clear(pdo);
|
||||
kfree(pdo);
|
||||
}
|
||||
ec_pdo_mapping_clear(&fsm->mapping);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -188,7 +166,7 @@ void ec_fsm_coe_map_action_next_sync(
|
||||
EC_DBG("Reading PDO mapping of sync manager %u of slave %u.\n",
|
||||
fsm->sync_index, slave->ring_position);
|
||||
|
||||
ec_fsm_coe_map_clear_pdos(fsm);
|
||||
ec_pdo_mapping_clear_pdos(&fsm->mapping);
|
||||
|
||||
if (!(entry = ec_sdo_get_entry(fsm->sync_sdo, 0))) {
|
||||
EC_ERR("SDO 0x%04X has no subindex 0 on slave %u.\n",
|
||||
@@ -269,15 +247,14 @@ void ec_fsm_coe_map_action_next_pdo(
|
||||
|
||||
{
|
||||
ec_sync_t *sync = fsm->slave->sii_syncs + fsm->sync_index;
|
||||
ec_pdo_t *pdo;
|
||||
|
||||
// exchange sync manager PDO mapping
|
||||
ec_sync_clear_pdos(sync);
|
||||
list_for_each_entry(pdo, &fsm->pdos, list) {
|
||||
ec_sync_add_pdo(sync, pdo);
|
||||
if (ec_pdo_mapping_copy(&sync->mapping, &fsm->mapping)) {
|
||||
fsm->state = ec_fsm_coe_map_state_error;
|
||||
return;
|
||||
}
|
||||
|
||||
sync->mapping_source = EC_SYNC_MAPPING_COE;
|
||||
ec_fsm_coe_map_clear_pdos(fsm);
|
||||
ec_pdo_mapping_clear_pdos(&fsm->mapping);
|
||||
|
||||
// next sync manager
|
||||
fsm->sync_index++;
|
||||
@@ -316,8 +293,8 @@ void ec_fsm_coe_map_state_pdo(
|
||||
|
||||
ec_pdo_init(fsm->pdo);
|
||||
fsm->pdo->index = EC_READ_U16(fsm->request.data);
|
||||
fsm->pdo->type =
|
||||
ec_sync_get_pdo_type(fsm->slave->sii_syncs + fsm->sync_index);
|
||||
fsm->pdo->dir =
|
||||
ec_sync_direction(fsm->slave->sii_syncs + fsm->sync_index);
|
||||
|
||||
if (fsm->slave->master->debug_level)
|
||||
EC_DBG(" PDO 0x%04X.\n", fsm->pdo->index);
|
||||
@@ -331,19 +308,11 @@ void ec_fsm_coe_map_state_pdo(
|
||||
return;
|
||||
}
|
||||
|
||||
if (fsm->pdo_sdo->name && strlen(fsm->pdo_sdo->name)) {
|
||||
if (!(fsm->pdo->name = (char *)
|
||||
kmalloc(strlen(fsm->pdo_sdo->name) + 1, GFP_KERNEL))) {
|
||||
EC_ERR("Failed to allocate PDO name.\n");
|
||||
ec_pdo_clear(fsm->pdo);
|
||||
kfree(fsm->pdo);
|
||||
fsm->state = ec_fsm_coe_map_state_error;
|
||||
return;
|
||||
}
|
||||
memcpy(fsm->pdo->name, fsm->pdo_sdo->name,
|
||||
strlen(fsm->pdo_sdo->name) + 1);
|
||||
} else {
|
||||
fsm->pdo->name = NULL;
|
||||
if (ec_pdo_set_name(fsm->pdo, fsm->pdo_sdo->name)) {
|
||||
ec_pdo_clear(fsm->pdo);
|
||||
kfree(fsm->pdo);
|
||||
fsm->state = ec_fsm_coe_map_state_error;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(entry = ec_sdo_get_entry(fsm->pdo_sdo, 0))) {
|
||||
@@ -356,7 +325,7 @@ void ec_fsm_coe_map_state_pdo(
|
||||
return;
|
||||
}
|
||||
|
||||
list_add_tail(&fsm->pdo->list, &fsm->pdos);
|
||||
list_add_tail(&fsm->pdo->list, &fsm->mapping.pdos);
|
||||
|
||||
ec_sdo_request_init_read(&fsm->request, entry);
|
||||
fsm->state = ec_fsm_coe_map_state_pdo_entry_count;
|
||||
@@ -463,28 +432,25 @@ void ec_fsm_coe_map_state_pdo_entry(
|
||||
return;
|
||||
}
|
||||
|
||||
ec_pdo_entry_init(pdo_entry);
|
||||
pdo_entry->index = pdo_entry_info >> 16;
|
||||
pdo_entry->subindex = (pdo_entry_info >> 8) & 0xFF;
|
||||
pdo_entry->bit_length = pdo_entry_info & 0xFF;
|
||||
|
||||
if (!pdo_entry->index && !pdo_entry->subindex) {
|
||||
char gapname[] = "Gap";
|
||||
|
||||
// we have a gap in the PDO, next PDO entry
|
||||
if (fsm->slave->master->debug_level) {
|
||||
EC_DBG(" PDO entry gap: %u bit.\n",
|
||||
pdo_entry->bit_length);
|
||||
}
|
||||
|
||||
if (!(pdo_entry->name = (char *)
|
||||
kmalloc(strlen(gapname) + 1, GFP_KERNEL))) {
|
||||
EC_ERR("Failed to allocate GAP entry name.\n");
|
||||
if (ec_pdo_entry_set_name(pdo_entry, "Gap")) {
|
||||
ec_pdo_entry_clear(pdo_entry);
|
||||
kfree(pdo_entry);
|
||||
fsm->state = ec_fsm_coe_map_state_error;
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(pdo_entry->name, gapname, strlen(gapname) + 1);
|
||||
list_add_tail(&pdo_entry->list, &fsm->pdo->entries);
|
||||
fsm->pdo_subindex++;
|
||||
ec_fsm_coe_map_action_next_pdo_entry(fsm);
|
||||
@@ -494,6 +460,7 @@ void ec_fsm_coe_map_state_pdo_entry(
|
||||
if (!(sdo = ec_slave_get_sdo(fsm->slave, pdo_entry->index))) {
|
||||
EC_ERR("Slave %u has no SDO 0x%04X.\n",
|
||||
fsm->slave->ring_position, pdo_entry->index);
|
||||
ec_pdo_entry_clear(pdo_entry);
|
||||
kfree(pdo_entry);
|
||||
fsm->state = ec_fsm_coe_map_state_error;
|
||||
return;
|
||||
@@ -503,27 +470,22 @@ void ec_fsm_coe_map_state_pdo_entry(
|
||||
EC_ERR("Slave %u has no SDO entry 0x%04X:%u.\n",
|
||||
fsm->slave->ring_position, pdo_entry->index,
|
||||
pdo_entry->subindex);
|
||||
ec_pdo_entry_clear(pdo_entry);
|
||||
kfree(pdo_entry);
|
||||
fsm->state = ec_fsm_coe_map_state_error;
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry->description && strlen(entry->description)) {
|
||||
if (!(pdo_entry->name = (char *)
|
||||
kmalloc(strlen(entry->description) + 1, GFP_KERNEL))) {
|
||||
EC_ERR("Failed to allocate PDO entry name.\n");
|
||||
kfree(pdo_entry);
|
||||
fsm->state = ec_fsm_coe_map_state_error;
|
||||
return;
|
||||
}
|
||||
memcpy(pdo_entry->name, entry->description, strlen(entry->description) + 1);
|
||||
} else {
|
||||
pdo_entry->name = NULL;
|
||||
if (ec_pdo_entry_set_name(pdo_entry, entry->description)) {
|
||||
ec_pdo_entry_clear(pdo_entry);
|
||||
kfree(pdo_entry);
|
||||
fsm->state = ec_fsm_coe_map_state_error;
|
||||
return;
|
||||
}
|
||||
|
||||
if (fsm->slave->master->debug_level) {
|
||||
EC_DBG(" PDO entry 0x%04X \"%s\" (%u bit).\n",
|
||||
pdo_entry->index, pdo_entry->name ? pdo_entry->name : "???",
|
||||
EC_DBG(" PDO entry 0x%04X \"%s\" (%u bit).\n", pdo_entry->index,
|
||||
pdo_entry->name ? pdo_entry->name : "???",
|
||||
pdo_entry->bit_length);
|
||||
}
|
||||
|
||||
|
||||
@@ -51,8 +51,8 @@
|
||||
typedef struct ec_fsm_coe_map ec_fsm_coe_map_t; /**< \see ec_fsm_coe_map */
|
||||
|
||||
/**
|
||||
* \todo doc
|
||||
*/
|
||||
|
||||
struct ec_fsm_coe_map
|
||||
{
|
||||
void (*state)(ec_fsm_coe_map_t *); /**< CoE mapping state function */
|
||||
@@ -66,7 +66,7 @@ struct ec_fsm_coe_map
|
||||
uint8_t sync_subindices; /**< number of mapped PDOs */
|
||||
uint16_t sync_subindex; /**< current subindex in mapping SDO */
|
||||
|
||||
struct list_head pdos; /**< list of mapped PDOs */
|
||||
ec_pdo_mapping_t mapping; /**< Mapping to apply. */
|
||||
ec_pdo_t *pdo; /**< current PDO */
|
||||
ec_sdo_t *pdo_sdo; /**< current PDO SDO */
|
||||
uint8_t pdo_subindices; /**< number of PDO entries */
|
||||
|
||||
+55
-70
@@ -31,16 +31,17 @@
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
\file
|
||||
EtherCAT PDO mapping state machine.
|
||||
*/
|
||||
/** \file
|
||||
* EtherCAT PDO mapping state machine.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#include "globals.h"
|
||||
#include "master.h"
|
||||
#include "mailbox.h"
|
||||
#include "slave_config.h"
|
||||
|
||||
#include "fsm_mapping.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -56,11 +57,10 @@ void ec_fsm_mapping_next_sync(ec_fsm_mapping_t *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
/** Constructor.
|
||||
*/
|
||||
|
||||
void ec_fsm_mapping_init(ec_fsm_mapping_t *fsm, /**< mapping state machine */
|
||||
void ec_fsm_mapping_init(
|
||||
ec_fsm_mapping_t *fsm, /**< mapping state machine */
|
||||
ec_fsm_coe_t *fsm_coe /**< CoE state machine to use */
|
||||
)
|
||||
{
|
||||
@@ -70,20 +70,18 @@ void ec_fsm_mapping_init(ec_fsm_mapping_t *fsm, /**< mapping state machine */
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
/** Destructor.
|
||||
*/
|
||||
|
||||
void ec_fsm_mapping_clear(ec_fsm_mapping_t *fsm /**< mapping state machine */)
|
||||
void ec_fsm_mapping_clear(
|
||||
ec_fsm_mapping_t *fsm /**< mapping state machine */
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Start PDO mapping configuration state machine.
|
||||
/** Start PDO mapping configuration state machine.
|
||||
*/
|
||||
|
||||
void ec_fsm_mapping_start(
|
||||
ec_fsm_mapping_t *fsm, /**< mapping state machine */
|
||||
ec_slave_t *slave /**< slave to configure */
|
||||
@@ -95,10 +93,10 @@ void ec_fsm_mapping_start(
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
/** Get running state.
|
||||
*
|
||||
* \return false, if state machine has terminated
|
||||
*/
|
||||
|
||||
int ec_fsm_mapping_running(
|
||||
const ec_fsm_mapping_t *fsm /**< mapping state machine */
|
||||
)
|
||||
@@ -109,13 +107,13 @@ int ec_fsm_mapping_running(
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Executes the current state of the state machine.
|
||||
/** Executes the current state of the state machine.
|
||||
*
|
||||
* If the state machine's datagram is not sent or received yet, the execution
|
||||
* of the state machine is delayed to the next cycle.
|
||||
*
|
||||
* \return false, if state machine has terminated
|
||||
*/
|
||||
|
||||
int ec_fsm_mapping_exec(
|
||||
ec_fsm_mapping_t *fsm /**< mapping state machine */
|
||||
)
|
||||
@@ -126,10 +124,10 @@ int ec_fsm_mapping_exec(
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
/** Get execution result.
|
||||
*
|
||||
* \return true, if the state machine terminated gracefully
|
||||
*/
|
||||
|
||||
int ec_fsm_mapping_success(
|
||||
const ec_fsm_mapping_t *fsm /**< mapping state machine */
|
||||
)
|
||||
@@ -138,27 +136,28 @@ int ec_fsm_mapping_success(
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* state functions
|
||||
* State functions.
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Start mapping configuration.
|
||||
/** Start mapping configuration.
|
||||
*/
|
||||
|
||||
void ec_fsm_mapping_state_start(
|
||||
ec_fsm_mapping_t *fsm /**< mapping state machine */
|
||||
)
|
||||
{
|
||||
if (!fsm->slave->config) {
|
||||
fsm->state = ec_fsm_mapping_state_end;
|
||||
return;
|
||||
}
|
||||
|
||||
fsm->dir = EC_DIR_OUTPUT;
|
||||
ec_fsm_mapping_next_sync(fsm);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Process mapping of next sync manager.
|
||||
/** Process mapping of next sync manager.
|
||||
*/
|
||||
|
||||
void ec_fsm_mapping_next_sync(
|
||||
ec_fsm_mapping_t *fsm /**< mapping state machine */
|
||||
)
|
||||
@@ -171,18 +170,25 @@ void ec_fsm_mapping_next_sync(
|
||||
}
|
||||
|
||||
if (!(fsm->sync = ec_slave_get_pdo_sync(fsm->slave, fsm->dir))) {
|
||||
// no sync manager found for this direction
|
||||
EC_WARN("next_sync(): No sync manager!\n");
|
||||
fsm->dir++;
|
||||
continue;
|
||||
}
|
||||
|
||||
fsm->dir++;
|
||||
if (fsm->sync->alt_mapping)
|
||||
fsm->mapping = &fsm->slave->config->mapping[fsm->dir];
|
||||
|
||||
if (ec_pdo_mapping_equal(&fsm->sync->mapping, fsm->mapping)) {
|
||||
// the mapping for this direction does not have to be altered
|
||||
fsm->dir++;
|
||||
continue;
|
||||
} else {
|
||||
fsm->dir++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fsm->slave->master->debug_level) {
|
||||
EC_DBG("Configuring PDO mapping for SM%u of slave %i.\n",
|
||||
EC_DBG("Configuring PDO mapping for SM%u of slave %u.\n",
|
||||
fsm->sync->index, fsm->slave->ring_position);
|
||||
}
|
||||
|
||||
@@ -201,34 +207,23 @@ void ec_fsm_mapping_next_sync(
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Process mapping of next PDO.
|
||||
/** Process mapping of next PDO.
|
||||
*/
|
||||
|
||||
ec_pdo_t *ec_fsm_mapping_next_pdo(
|
||||
ec_fsm_mapping_t *fsm, /**< mapping state machine */
|
||||
struct list_head *list /**< current PDO list item */
|
||||
const ec_fsm_mapping_t *fsm, /**< mapping state machine */
|
||||
const struct list_head *list /**< current PDO list item */
|
||||
)
|
||||
{
|
||||
ec_pdo_t *pdo;
|
||||
|
||||
do {
|
||||
list = list->next;
|
||||
if (list == &fsm->sync->pdos)
|
||||
return NULL; // no next PDO
|
||||
pdo = list_entry(list, ec_pdo_t, list);
|
||||
}
|
||||
while (pdo->sync_index != fsm->sync->index);
|
||||
|
||||
return pdo;
|
||||
list = list->next;
|
||||
if (list == &fsm->mapping->pdos)
|
||||
return NULL; // no next PDO
|
||||
return list_entry(list, ec_pdo_t, list);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Set the number of mapped PDOs to zero.
|
||||
/** Set the number of mapped PDOs to zero.
|
||||
*/
|
||||
|
||||
void ec_fsm_mapping_state_zero_count(
|
||||
ec_fsm_mapping_t *fsm /**< mapping state machine */
|
||||
)
|
||||
@@ -245,8 +240,7 @@ void ec_fsm_mapping_state_zero_count(
|
||||
// map all PDOs belonging to the current sync manager
|
||||
|
||||
// find first PDO
|
||||
if (!(fsm->pdo = ec_fsm_mapping_next_pdo(
|
||||
fsm, &fsm->sync->pdos))) {
|
||||
if (!(fsm->pdo = ec_fsm_mapping_next_pdo(fsm, &fsm->mapping->pdos))) {
|
||||
if (fsm->slave->master->debug_level)
|
||||
EC_DBG("No PDOs to map for SM%u of slave %u.\n",
|
||||
fsm->sync->index, fsm->slave->ring_position);
|
||||
@@ -271,10 +265,8 @@ void ec_fsm_mapping_state_zero_count(
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Add a PDO to the sync managers mapping.
|
||||
/** Add a PDO to the sync managers mapping.
|
||||
*/
|
||||
|
||||
void ec_fsm_mapping_state_add_pdo(
|
||||
ec_fsm_mapping_t *fsm /**< mapping state machine */
|
||||
)
|
||||
@@ -289,8 +281,7 @@ void ec_fsm_mapping_state_add_pdo(
|
||||
}
|
||||
|
||||
// find next PDO
|
||||
if (!(fsm->pdo = ec_fsm_mapping_next_pdo(
|
||||
fsm, &fsm->pdo->list))) {
|
||||
if (!(fsm->pdo = ec_fsm_mapping_next_pdo(fsm, &fsm->pdo->list))) {
|
||||
// no more PDOs to map. write PDO count
|
||||
fsm->sdodata.subindex = 0;
|
||||
EC_WRITE_U8(&fsm->sdo_value, fsm->pdo_count);
|
||||
@@ -322,10 +313,8 @@ void ec_fsm_mapping_state_add_pdo(
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Set the number of mapped PDOs.
|
||||
/** Set the number of mapped PDOs.
|
||||
*/
|
||||
|
||||
void ec_fsm_mapping_state_pdo_count(
|
||||
ec_fsm_mapping_t *fsm /**< mapping state machine */
|
||||
)
|
||||
@@ -351,10 +340,8 @@ void ec_fsm_mapping_state_pdo_count(
|
||||
* Common state functions
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
State: ERROR.
|
||||
*/
|
||||
|
||||
/** State: ERROR.
|
||||
*/
|
||||
void ec_fsm_mapping_state_error(
|
||||
ec_fsm_mapping_t *fsm /**< mapping state machine */
|
||||
)
|
||||
@@ -363,10 +350,8 @@ void ec_fsm_mapping_state_error(
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
State: END.
|
||||
*/
|
||||
|
||||
/** State: END.
|
||||
*/
|
||||
void ec_fsm_mapping_state_end(
|
||||
ec_fsm_mapping_t *fsm /**< mapping state machine */
|
||||
)
|
||||
|
||||
@@ -63,6 +63,7 @@ struct ec_fsm_mapping
|
||||
|
||||
ec_direction_t dir; /**< current PDO direction */
|
||||
ec_sync_t *sync; /**< current sync manager */
|
||||
const ec_pdo_mapping_t *mapping; /**< Mapping to assign. */
|
||||
ec_pdo_t *pdo; /**< current PDO */
|
||||
ec_sdo_data_t sdodata; /**< SDO configuration data */
|
||||
uint16_t sdo_value; /**< SDO value */
|
||||
|
||||
+6
-4
@@ -205,7 +205,7 @@ void ec_fsm_master_state_broadcast(ec_fsm_master_t *fsm /**< master state machin
|
||||
fsm->topology_change_pending = 1;
|
||||
fsm->slaves_responding = datagram->working_counter;
|
||||
|
||||
EC_INFO("%i slave%s responding.\n",
|
||||
EC_INFO("%u slave%s responding.\n",
|
||||
fsm->slaves_responding,
|
||||
fsm->slaves_responding == 1 ? "" : "s");
|
||||
|
||||
@@ -483,12 +483,11 @@ void ec_fsm_master_action_process_states(ec_fsm_master_t *fsm
|
||||
down(&master->config_sem);
|
||||
if (!master->allow_config) {
|
||||
up(&master->config_sem);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
master->config_state = EC_REQUEST_IN_PROGRESS;
|
||||
fsm->config_error = 0;
|
||||
up(&master->config_sem);
|
||||
|
||||
|
||||
// check for pending slave configurations
|
||||
if (ec_fsm_master_action_configure(fsm))
|
||||
return;
|
||||
@@ -911,6 +910,9 @@ void ec_fsm_master_state_scan_slaves(
|
||||
EC_INFO("Bus scanning completed in %u ms.\n",
|
||||
(u32) (jiffies - fsm->scan_jiffies) * 1000 / HZ);
|
||||
|
||||
// Attach slave configurations
|
||||
ec_master_attach_slave_configs(master);
|
||||
|
||||
#ifdef EC_EOE
|
||||
// check if EoE processing has to be started
|
||||
ec_master_eoe_start(master);
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@
|
||||
#include "globals.h"
|
||||
#include "../include/ecrt.h"
|
||||
#include "datagram.h"
|
||||
#include "slave.h"
|
||||
//#include "slave.h"
|
||||
#include "canopen.h"
|
||||
|
||||
#include "fsm_slave.h"
|
||||
|
||||
+69
-38
@@ -41,8 +41,9 @@
|
||||
#include "globals.h"
|
||||
#include "master.h"
|
||||
#include "mailbox.h"
|
||||
#include "fsm_slave.h"
|
||||
#include "fsm_mapping.h"
|
||||
#include "slave_config.h"
|
||||
#include "fsm_slave.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@@ -569,12 +570,12 @@ void ec_fsm_slave_scan_state_eeprom_data(ec_fsm_slave_t *fsm /**< slave state ma
|
||||
break;
|
||||
case 0x0032:
|
||||
if (ec_slave_fetch_sii_pdos( slave, (uint8_t *) cat_word,
|
||||
cat_size * 2, EC_TX_PDO))
|
||||
cat_size * 2, EC_DIR_INPUT)) // TxPdo
|
||||
goto end;
|
||||
break;
|
||||
case 0x0033:
|
||||
if (ec_slave_fetch_sii_pdos( slave, (uint8_t *) cat_word,
|
||||
cat_size * 2, EC_RX_PDO))
|
||||
cat_size * 2, EC_DIR_OUTPUT)) // RxPdo
|
||||
goto end;
|
||||
break;
|
||||
default:
|
||||
@@ -662,8 +663,8 @@ void ec_fsm_slave_conf_state_init(ec_fsm_slave_t *fsm /**< slave state machine *
|
||||
|
||||
// clear FMMU configurations
|
||||
ec_datagram_npwr(datagram, slave->station_address,
|
||||
0x0600, EC_FMMU_SIZE * slave->base_fmmu_count);
|
||||
memset(datagram->data, 0x00, EC_FMMU_SIZE * slave->base_fmmu_count);
|
||||
0x0600, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count);
|
||||
memset(datagram->data, 0x00, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count);
|
||||
fsm->retries = EC_FSM_RETRIES;
|
||||
fsm->state = ec_fsm_slave_conf_state_clear_fmmus;
|
||||
}
|
||||
@@ -729,7 +730,7 @@ void ec_fsm_slave_conf_enter_mbox_sync(
|
||||
if (!slave->sii_mailbox_protocols) {
|
||||
// no mailbox protocols supported
|
||||
if (master->debug_level)
|
||||
EC_DBG("Slave %i does not support mailbox communication.\n",
|
||||
EC_DBG("Slave %u does not support mailbox communication.\n",
|
||||
slave->ring_position);
|
||||
ec_fsm_slave_conf_enter_preop(fsm);
|
||||
return;
|
||||
@@ -740,41 +741,41 @@ void ec_fsm_slave_conf_enter_mbox_sync(
|
||||
slave->ring_position);
|
||||
}
|
||||
|
||||
if (slave->sii_sync_count >= 2) {
|
||||
// configure sync managers
|
||||
if (slave->sii_sync_count >= 2) { // mailbox configuration provided
|
||||
ec_datagram_npwr(datagram, slave->station_address, 0x0800,
|
||||
EC_SYNC_SIZE * slave->sii_sync_count);
|
||||
memset(datagram->data, 0x00, EC_SYNC_SIZE * slave->sii_sync_count);
|
||||
EC_SYNC_PAGE_SIZE * slave->sii_sync_count);
|
||||
memset(datagram->data, 0x00,
|
||||
EC_SYNC_PAGE_SIZE * slave->sii_sync_count);
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
ec_sync_config(&slave->sii_syncs[i],
|
||||
datagram->data + EC_SYNC_SIZE * i);
|
||||
ec_sync_config(&slave->sii_syncs[i], slave->sii_syncs[i].length,
|
||||
datagram->data + EC_SYNC_PAGE_SIZE * i);
|
||||
}
|
||||
} else { // no mailbox sync manager configurations provided
|
||||
ec_sync_t sync;
|
||||
|
||||
if (master->debug_level)
|
||||
EC_DBG("Slave %i does not provide"
|
||||
EC_DBG("Slave %u does not provide"
|
||||
" mailbox sync manager configurations.\n",
|
||||
slave->ring_position);
|
||||
|
||||
ec_datagram_npwr(datagram, slave->station_address, 0x0800,
|
||||
EC_SYNC_SIZE * 2);
|
||||
memset(datagram->data, 0x00, EC_SYNC_SIZE * 2);
|
||||
EC_SYNC_PAGE_SIZE * 2);
|
||||
memset(datagram->data, 0x00, EC_SYNC_PAGE_SIZE * 2);
|
||||
|
||||
ec_sync_init(&sync, slave, 0);
|
||||
sync.physical_start_address = slave->sii_rx_mailbox_offset;
|
||||
sync.length = slave->sii_rx_mailbox_size;
|
||||
sync.control_register = 0x26;
|
||||
sync.enable = 1;
|
||||
ec_sync_config(&sync, datagram->data + EC_SYNC_SIZE * sync.index);
|
||||
ec_sync_config(&sync, slave->sii_rx_mailbox_size,
|
||||
datagram->data + EC_SYNC_PAGE_SIZE * sync.index);
|
||||
|
||||
ec_sync_init(&sync, slave, 1);
|
||||
sync.physical_start_address = slave->sii_tx_mailbox_offset;
|
||||
sync.length = slave->sii_tx_mailbox_size;
|
||||
sync.control_register = 0x22;
|
||||
sync.enable = 1;
|
||||
ec_sync_config(&sync, datagram->data + EC_SYNC_SIZE * sync.index);
|
||||
ec_sync_config(&sync, slave->sii_tx_mailbox_size,
|
||||
datagram->data + EC_SYNC_PAGE_SIZE * sync.index);
|
||||
}
|
||||
|
||||
fsm->retries = EC_FSM_RETRIES;
|
||||
@@ -877,15 +878,22 @@ void ec_fsm_slave_conf_enter_sdoconf(ec_fsm_slave_t *fsm /**< slave state machin
|
||||
{
|
||||
ec_slave_t *slave = fsm->slave;
|
||||
|
||||
// No CoE configuration to be applied?
|
||||
if (list_empty(&slave->sdo_confs)) { // skip SDO configuration
|
||||
if (!slave->config) {
|
||||
EC_DBG("Slave %u is not configured.\n", slave->ring_position);
|
||||
ec_fsm_slave_conf_enter_saveop(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
// No CoE configuration to be applied? FIXME
|
||||
if (list_empty(&slave->config->sdo_configs)) { // skip SDO configuration
|
||||
ec_fsm_slave_conf_enter_mapconf(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
// start SDO configuration
|
||||
fsm->state = ec_fsm_slave_conf_state_sdoconf;
|
||||
fsm->sdodata = list_entry(fsm->slave->sdo_confs.next, ec_sdo_data_t, list);
|
||||
fsm->sdodata =
|
||||
list_entry(fsm->slave->config->sdo_configs.next, ec_sdo_data_t, list);
|
||||
ec_fsm_coe_download(&fsm->fsm_coe, fsm->slave, fsm->sdodata);
|
||||
ec_fsm_coe_exec(&fsm->fsm_coe); // execute immediately
|
||||
}
|
||||
@@ -911,9 +919,9 @@ void ec_fsm_slave_conf_state_sdoconf(
|
||||
}
|
||||
|
||||
// Another SDO to configure?
|
||||
if (fsm->sdodata->list.next != &fsm->slave->sdo_confs) {
|
||||
fsm->sdodata = list_entry(fsm->sdodata->list.next,
|
||||
ec_sdo_data_t, list);
|
||||
if (fsm->sdodata->list.next != &fsm->slave->config->sdo_configs) {
|
||||
fsm->sdodata =
|
||||
list_entry(fsm->sdodata->list.next, ec_sdo_data_t, list);
|
||||
ec_fsm_coe_download(&fsm->fsm_coe, fsm->slave, fsm->sdodata);
|
||||
ec_fsm_coe_exec(&fsm->fsm_coe); // execute immediately
|
||||
return;
|
||||
@@ -982,21 +990,34 @@ void ec_fsm_slave_conf_enter_pdo_sync(
|
||||
{
|
||||
ec_slave_t *slave = fsm->slave;
|
||||
ec_datagram_t *datagram = fsm->datagram;
|
||||
unsigned int i;
|
||||
unsigned int i, offset, num_syncs;
|
||||
const ec_sync_t *sync;
|
||||
ec_direction_t dir;
|
||||
uint16_t size;
|
||||
|
||||
if (!slave->sii_sync_count) {
|
||||
ec_fsm_slave_conf_enter_fmmu(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
// configure sync managers for process data
|
||||
ec_datagram_npwr(datagram, slave->station_address, 0x0800,
|
||||
EC_SYNC_SIZE * slave->sii_sync_count);
|
||||
memset(datagram->data, 0x00, EC_SYNC_SIZE * slave->sii_sync_count);
|
||||
if (slave->sii_mailbox_protocols) {
|
||||
offset = 2; // slave has mailboxes
|
||||
} else {
|
||||
offset = 0;
|
||||
}
|
||||
num_syncs = slave->sii_sync_count - offset;
|
||||
|
||||
for (i = 0; i < slave->sii_sync_count; i++) {
|
||||
ec_sync_config(&slave->sii_syncs[i],
|
||||
datagram->data + EC_SYNC_SIZE * i);
|
||||
// configure sync managers for process data
|
||||
ec_datagram_npwr(datagram, slave->station_address,
|
||||
0x0800 + EC_SYNC_PAGE_SIZE * offset,
|
||||
EC_SYNC_PAGE_SIZE * num_syncs);
|
||||
memset(datagram->data, 0x00, EC_SYNC_PAGE_SIZE * num_syncs);
|
||||
|
||||
for (i = 0; i < num_syncs; i++) {
|
||||
sync = &slave->sii_syncs[i + offset];
|
||||
dir = ec_sync_direction(sync);
|
||||
size = ec_pdo_mapping_total_size(&slave->config->mapping[dir]);
|
||||
ec_sync_config(sync, size, datagram->data + EC_SYNC_PAGE_SIZE * i);
|
||||
}
|
||||
|
||||
fsm->retries = EC_FSM_RETRIES;
|
||||
@@ -1047,7 +1068,9 @@ void ec_fsm_slave_conf_enter_fmmu(ec_fsm_slave_t *fsm /**< slave state machine *
|
||||
{
|
||||
ec_slave_t *slave = fsm->slave;
|
||||
ec_datagram_t *datagram = fsm->datagram;
|
||||
unsigned int j;
|
||||
unsigned int i;
|
||||
const ec_fmmu_config_t *fmmu;
|
||||
const ec_sync_t *sync;
|
||||
|
||||
if (!slave->base_fmmu_count) { // skip FMMU configuration
|
||||
ec_fsm_slave_conf_enter_saveop(fsm);
|
||||
@@ -1056,10 +1079,18 @@ void ec_fsm_slave_conf_enter_fmmu(ec_fsm_slave_t *fsm /**< slave state machine *
|
||||
|
||||
// configure FMMUs
|
||||
ec_datagram_npwr(datagram, slave->station_address,
|
||||
0x0600, EC_FMMU_SIZE * slave->base_fmmu_count);
|
||||
memset(datagram->data, 0x00, EC_FMMU_SIZE * slave->base_fmmu_count);
|
||||
for (j = 0; j < slave->fmmu_count; j++) {
|
||||
ec_fmmu_config(&slave->fmmus[j], datagram->data + EC_FMMU_SIZE * j);
|
||||
0x0600, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count);
|
||||
memset(datagram->data, 0x00, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count);
|
||||
for (i = 0; i < slave->config->used_fmmus; i++) {
|
||||
fmmu = &slave->config->fmmu_configs[i];
|
||||
if (!(sync = ec_slave_get_pdo_sync(slave, fmmu->dir))) {
|
||||
fsm->state = ec_fsm_slave_state_error;
|
||||
EC_ERR("Failed to determine PDO sync manager for FMMU on slave"
|
||||
" %u!\n", slave->ring_position);
|
||||
return;
|
||||
}
|
||||
ec_fmmu_config_page(fmmu, sync,
|
||||
datagram->data + EC_FMMU_PAGE_SIZE * i);
|
||||
}
|
||||
|
||||
fsm->retries = EC_FSM_RETRIES;
|
||||
|
||||
+78
-74
@@ -31,10 +31,9 @@
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
\file
|
||||
Global definitions and macros.
|
||||
*/
|
||||
/** \file
|
||||
* Global definitions and macros.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@@ -46,112 +45,121 @@
|
||||
#include "../globals.h"
|
||||
|
||||
/******************************************************************************
|
||||
* EtherCAT master
|
||||
* EtherCAT master
|
||||
*****************************************************************************/
|
||||
|
||||
/** clock frequency for the EoE state machines */
|
||||
/** Clock frequency for the EoE state machines. */
|
||||
#define EC_EOE_FREQUENCY 1000
|
||||
|
||||
/** datagram timeout in microseconds */
|
||||
/** Datagram timeout in microseconds. */
|
||||
#define EC_IO_TIMEOUT 500
|
||||
|
||||
/** number of state machine retries on datagram timeout */
|
||||
/** Number of state machine retries on datagram timeout. */
|
||||
#define EC_FSM_RETRIES 3
|
||||
|
||||
/** Seconds to wait before fetching SDO dictionary
|
||||
after slave entered PREOP state. */
|
||||
#define EC_WAIT_SDO_DICT 3
|
||||
|
||||
/** minimum size of a buffer used with ec_state_string() */
|
||||
/** Minimum size of a buffer used with ec_state_string(). */
|
||||
#define EC_STATE_STRING_SIZE 32
|
||||
|
||||
/** maximum EEPROM size in words, to avoid infinite reading. */
|
||||
/** Maximum EEPROM size in words, to avoid infinite reading. */
|
||||
#define EC_MAX_EEPROM_SIZE 1024
|
||||
|
||||
/******************************************************************************
|
||||
* EtherCAT protocol
|
||||
* EtherCAT protocol
|
||||
*****************************************************************************/
|
||||
|
||||
/** size of an EtherCAT frame header */
|
||||
/** Size of an EtherCAT frame header. */
|
||||
#define EC_FRAME_HEADER_SIZE 2
|
||||
|
||||
/** size of an EtherCAT datagram header */
|
||||
/** Size of an EtherCAT datagram header. */
|
||||
#define EC_DATAGRAM_HEADER_SIZE 10
|
||||
|
||||
/** size of an EtherCAT datagram footer */
|
||||
/** Size of an EtherCAT datagram footer. */
|
||||
#define EC_DATAGRAM_FOOTER_SIZE 2
|
||||
|
||||
/** size of the EtherCAT address field */
|
||||
/** Size of the EtherCAT address field. */
|
||||
#define EC_ADDR_LEN 4
|
||||
|
||||
/** resulting maximum data size of a single datagram in a frame */
|
||||
/** Resulting maximum data size of a single datagram in a frame. */
|
||||
#define EC_MAX_DATA_SIZE (ETH_DATA_LEN - EC_FRAME_HEADER_SIZE \
|
||||
- EC_DATAGRAM_HEADER_SIZE - EC_DATAGRAM_FOOTER_SIZE)
|
||||
|
||||
/** word offset of first EEPROM category. */
|
||||
/** Word offset of first EEPROM category. */
|
||||
#define EC_FIRST_EEPROM_CATEGORY_OFFSET 0x40
|
||||
|
||||
/** Size of a sync manager configuration page. */
|
||||
#define EC_SYNC_PAGE_SIZE 8
|
||||
|
||||
/** Maximum number of FMMUs per slave. */
|
||||
#define EC_MAX_FMMUS 16
|
||||
|
||||
/** Size of an FMMU configuration page. */
|
||||
#define EC_FMMU_PAGE_SIZE 16
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Convenience macro for printing EtherCAT-specific information to syslog.
|
||||
This will print the message in \a fmt with a prefixed "EtherCAT: ".
|
||||
\param fmt format string (like in printf())
|
||||
\param args arguments (optional)
|
||||
*/
|
||||
|
||||
/** Convenience macro for printing EtherCAT-specific information to syslog.
|
||||
*
|
||||
* This will print the message in \a fmt with a prefixed "EtherCAT: ".
|
||||
*
|
||||
* \param fmt format string (like in printf())
|
||||
* \param args arguments (optional)
|
||||
*/
|
||||
#define EC_INFO(fmt, args...) \
|
||||
printk(KERN_INFO "EtherCAT: " fmt, ##args)
|
||||
|
||||
/**
|
||||
Convenience macro for printing EtherCAT-specific errors to syslog.
|
||||
This will print the message in \a fmt with a prefixed "EtherCAT ERROR: ".
|
||||
\param fmt format string (like in printf())
|
||||
\param args arguments (optional)
|
||||
*/
|
||||
|
||||
/** Convenience macro for printing EtherCAT-specific errors to syslog.
|
||||
*
|
||||
* This will print the message in \a fmt with a prefixed "EtherCAT ERROR: ".
|
||||
*
|
||||
* \param fmt format string (like in printf())
|
||||
* \param args arguments (optional)
|
||||
*/
|
||||
#define EC_ERR(fmt, args...) \
|
||||
printk(KERN_ERR "EtherCAT ERROR: " fmt, ##args)
|
||||
|
||||
/**
|
||||
Convenience macro for printing EtherCAT-specific warnings to syslog.
|
||||
This will print the message in \a fmt with a prefixed "EtherCAT WARNING: ".
|
||||
\param fmt format string (like in printf())
|
||||
\param args arguments (optional)
|
||||
*/
|
||||
|
||||
/** Convenience macro for printing EtherCAT-specific warnings to syslog.
|
||||
*
|
||||
* This will print the message in \a fmt with a prefixed "EtherCAT WARNING: ".
|
||||
*
|
||||
* \param fmt format string (like in printf())
|
||||
* \param args arguments (optional)
|
||||
*/
|
||||
#define EC_WARN(fmt, args...) \
|
||||
printk(KERN_WARNING "EtherCAT WARNING: " fmt, ##args)
|
||||
|
||||
/**
|
||||
Convenience macro for printing EtherCAT debug messages to syslog.
|
||||
This will print the message in \a fmt with a prefixed "EtherCAT DEBUG: ".
|
||||
\param fmt format string (like in printf())
|
||||
\param args arguments (optional)
|
||||
*/
|
||||
|
||||
/** Convenience macro for printing EtherCAT debug messages to syslog.
|
||||
*
|
||||
* This will print the message in \a fmt with a prefixed "EtherCAT DEBUG: ".
|
||||
*
|
||||
* \param fmt format string (like in printf())
|
||||
* \param args arguments (optional)
|
||||
*/
|
||||
#define EC_DBG(fmt, args...) \
|
||||
printk(KERN_DEBUG "EtherCAT DEBUG: " fmt, ##args)
|
||||
|
||||
/**
|
||||
Convenience macro for defining read-only SysFS attributes.
|
||||
This results in creating a static variable called attr_\a NAME. The SysFS
|
||||
file will be world-readable.
|
||||
\param NAME name of the attribute to create.
|
||||
*/
|
||||
|
||||
/** Convenience macro for defining read-only SysFS attributes.
|
||||
*
|
||||
* This results in creating a static variable called attr_\a NAME. The SysFS
|
||||
* file will be world-readable.
|
||||
*
|
||||
* \param NAME name of the attribute to create.
|
||||
*/
|
||||
#define EC_SYSFS_READ_ATTR(NAME) \
|
||||
static struct attribute attr_##NAME = { \
|
||||
.name = EC_STR(NAME), .owner = THIS_MODULE, .mode = S_IRUGO \
|
||||
}
|
||||
|
||||
/**
|
||||
Convenience macro for defining read-write SysFS attributes.
|
||||
This results in creating a static variable called attr_\a NAME. The SysFS
|
||||
file will be word-readable plus owner-writable.
|
||||
\param NAME name of the attribute to create.
|
||||
*/
|
||||
|
||||
/** Convenience macro for defining read-write SysFS attributes.
|
||||
*
|
||||
* This results in creating a static variable called attr_\a NAME. The SysFS
|
||||
* file will be word-readable plus owner-writable.
|
||||
*
|
||||
* \param NAME name of the attribute to create.
|
||||
*/
|
||||
#define EC_SYSFS_READ_WRITE_ATTR(NAME) \
|
||||
static struct attribute attr_##NAME = { \
|
||||
.name = EC_STR(NAME), .owner = THIS_MODULE, .mode = S_IRUGO | S_IWUSR \
|
||||
@@ -171,27 +179,22 @@ int ec_mac_is_zero(const uint8_t *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Code - Message pair.
|
||||
Some EtherCAT datagrams support reading a status code to display a certain
|
||||
message. This type allows to map a code to a message string.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t code; /**< code */
|
||||
const char *message; /**< message belonging to \a code */
|
||||
/** Code - Message pair.
|
||||
*
|
||||
* Some EtherCAT datagrams support reading a status code to display a certain
|
||||
* message. This type allows to map a code to a message string.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t code; /**< Code. */
|
||||
const char *message; /**< Message belonging to \a code. */
|
||||
}
|
||||
ec_code_msg_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Master request state.
|
||||
/** Master request state.
|
||||
*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
typedef enum {
|
||||
EC_REQUEST_QUEUED,
|
||||
EC_REQUEST_IN_PROGRESS,
|
||||
EC_REQUEST_COMPLETE,
|
||||
@@ -201,6 +204,7 @@ ec_request_state_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct ec_slave ec_slave_t; /**< \see ec_slave. */
|
||||
typedef struct ec_sdo ec_sdo_t; /**< \see ec_sdo */
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
+118
-194
@@ -46,16 +46,18 @@
|
||||
|
||||
#include "../include/ecrt.h"
|
||||
#include "globals.h"
|
||||
#include "master.h"
|
||||
#include "slave.h"
|
||||
#include "slave_config.h"
|
||||
#include "device.h"
|
||||
#include "datagram.h"
|
||||
#ifdef EC_EOE
|
||||
#include "ethernet.h"
|
||||
#endif
|
||||
#include "master.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_master_destroy_slave_configs(ec_master_t *);
|
||||
void ec_master_destroy_domains(ec_master_t *);
|
||||
static int ec_master_idle_thread(ec_master_t *);
|
||||
static int ec_master_operation_thread(ec_master_t *);
|
||||
@@ -122,6 +124,8 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT master */
|
||||
INIT_LIST_HEAD(&master->slaves);
|
||||
master->slave_count = 0;
|
||||
|
||||
INIT_LIST_HEAD(&master->configs);
|
||||
|
||||
master->scan_state = EC_REQUEST_IN_PROGRESS;
|
||||
master->allow_scan = 1;
|
||||
init_MUTEX(&master->scan_sem);
|
||||
@@ -136,12 +140,14 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT master */
|
||||
master->datagram_index = 0;
|
||||
|
||||
INIT_LIST_HEAD(&master->domains);
|
||||
master->debug_level = 0;
|
||||
|
||||
master->debug_level = 0;
|
||||
master->stats.timeouts = 0;
|
||||
master->stats.corrupted = 0;
|
||||
master->stats.unmatched = 0;
|
||||
master->stats.output_jiffies = 0;
|
||||
master->pdo_slaves_offline = 0; // assume all PDO slaves online
|
||||
master->frames_timed_out = 0;
|
||||
|
||||
for (i = 0; i < HZ; i++) {
|
||||
master->idle_cycle_times[i] = 0;
|
||||
@@ -236,6 +242,7 @@ void ec_master_clear(
|
||||
#ifdef EC_EOE
|
||||
ec_master_clear_eoe_handlers(master);
|
||||
#endif
|
||||
ec_master_destroy_slave_configs(master);
|
||||
ec_master_destroy_slaves(master);
|
||||
ec_master_destroy_domains(master);
|
||||
ec_fsm_master_clear(&master->fsm);
|
||||
@@ -251,10 +258,8 @@ void ec_master_clear(
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifdef EC_EOE
|
||||
/**
|
||||
* Clear and free all EoE handlers.
|
||||
/** Clear and free all EoE handlers.
|
||||
*/
|
||||
|
||||
void ec_master_clear_eoe_handlers(
|
||||
ec_master_t *master /**< EtherCAT master */
|
||||
)
|
||||
@@ -271,15 +276,27 @@ void ec_master_clear_eoe_handlers(
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Destroy all slaves.
|
||||
*/
|
||||
/** Destroy all slave configurations.
|
||||
*/
|
||||
void ec_master_destroy_slave_configs(ec_master_t *master)
|
||||
{
|
||||
ec_slave_config_t *sc, *next;
|
||||
|
||||
list_for_each_entry_safe(sc, next, &master->configs, list) {
|
||||
list_del(&sc->list);
|
||||
ec_slave_config_destroy(sc);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Destroy all slaves.
|
||||
*/
|
||||
void ec_master_destroy_slaves(ec_master_t *master)
|
||||
{
|
||||
ec_slave_t *slave, *next_slave;
|
||||
ec_slave_t *slave, *next;
|
||||
|
||||
list_for_each_entry_safe(slave, next_slave, &master->slaves, list) {
|
||||
list_for_each_entry_safe(slave, next, &master->slaves, list) {
|
||||
list_del(&slave->list);
|
||||
ec_slave_destroy(slave);
|
||||
}
|
||||
@@ -295,9 +312,9 @@ void ec_master_destroy_slaves(ec_master_t *master)
|
||||
|
||||
void ec_master_destroy_domains(ec_master_t *master)
|
||||
{
|
||||
ec_domain_t *domain, *next_d;
|
||||
ec_domain_t *domain, *next;
|
||||
|
||||
list_for_each_entry_safe(domain, next_d, &master->domains, list) {
|
||||
list_for_each_entry_safe(domain, next, &master->domains, list) {
|
||||
list_del(&domain->list);
|
||||
ec_domain_destroy(domain);
|
||||
}
|
||||
@@ -467,8 +484,6 @@ int ec_master_enter_operation_mode(ec_master_t *master /**< EtherCAT master */)
|
||||
EC_DBG("Switching to operation mode.\n");
|
||||
|
||||
master->mode = EC_MASTER_MODE_OPERATION;
|
||||
master->pdo_slaves_offline = 0; // assume all PDO slaves online
|
||||
master->frames_timed_out = 0;
|
||||
master->ext_request_cb = NULL;
|
||||
master->ext_release_cb = NULL;
|
||||
master->ext_cb_data = NULL;
|
||||
@@ -505,9 +520,11 @@ void ec_master_leave_operation_mode(ec_master_t *master
|
||||
master->release_cb = ec_master_release_cb;
|
||||
master->cb_data = master;
|
||||
|
||||
ec_master_destroy_slave_configs(master);
|
||||
ec_master_destroy_domains(master);
|
||||
|
||||
// set states for all slaves
|
||||
list_for_each_entry(slave, &master->slaves, list) {
|
||||
ec_slave_reset(slave);
|
||||
ec_slave_request_state(slave, EC_SLAVE_STATE_PREOP);
|
||||
}
|
||||
#ifdef EC_EOE
|
||||
@@ -518,8 +535,6 @@ void ec_master_leave_operation_mode(ec_master_t *master
|
||||
}
|
||||
#endif
|
||||
|
||||
ec_master_destroy_domains(master);
|
||||
|
||||
if (ec_master_thread_start(master, ec_master_idle_thread))
|
||||
EC_WARN("Failed to restart master thread!\n");
|
||||
#ifdef EC_EOE
|
||||
@@ -1241,101 +1256,51 @@ void ec_master_prepare(ec_master_t *master /**< EtherCAT master */)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Translates an ASCII coded bus-address to a slave pointer.
|
||||
* These are the valid addressing schemes:
|
||||
* - \a "X" = the Xth slave on the bus (ring position),
|
||||
* - \a "#X" = the slave with alias X,
|
||||
* - \a "#X:Y" = the Yth slave after the slave with alias X.
|
||||
* X and Y are zero-based indices and may be provided in hexadecimal or octal
|
||||
* notation (with appropriate prefix).
|
||||
* \return pointer to the slave on success, else NULL
|
||||
/** Detaches the slave configurations from the slaves.
|
||||
*/
|
||||
|
||||
ec_slave_t *ec_master_parse_slave_address(
|
||||
const ec_master_t *master, /**< EtherCAT master */
|
||||
const char *address /**< address string */
|
||||
void ec_master_detach_slave_configs(
|
||||
ec_master_t *master /**< EtherCAT master. */
|
||||
)
|
||||
{
|
||||
unsigned long first, second;
|
||||
char *remainder, *remainder2;
|
||||
const char *original;
|
||||
unsigned int alias_requested = 0, alias_not_found = 1;
|
||||
ec_slave_t *alias_slave = NULL, *slave;
|
||||
ec_slave_config_t *sc;
|
||||
|
||||
original = address;
|
||||
if (!master->configs_attached)
|
||||
return;
|
||||
|
||||
if (!address[0])
|
||||
goto out_invalid;
|
||||
|
||||
if (address[0] == '#') {
|
||||
alias_requested = 1;
|
||||
address++;
|
||||
list_for_each_entry(sc, &master->configs, list) {
|
||||
ec_slave_config_detach(sc);
|
||||
}
|
||||
|
||||
first = simple_strtoul(address, &remainder, 0);
|
||||
if (remainder == address)
|
||||
goto out_invalid;
|
||||
master->configs_attached = 0;
|
||||
}
|
||||
|
||||
if (alias_requested) {
|
||||
list_for_each_entry(alias_slave, &master->slaves, list) {
|
||||
if (alias_slave->sii_alias == first) {
|
||||
alias_not_found = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (alias_not_found) {
|
||||
EC_ERR("Alias not found!\n");
|
||||
goto out_invalid;
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Attaches the slave configurations to the slaves.
|
||||
*/
|
||||
int ec_master_attach_slave_configs(
|
||||
ec_master_t *master /**< EtherCAT master. */
|
||||
)
|
||||
{
|
||||
ec_slave_config_t *sc;
|
||||
unsigned int errors = 0;
|
||||
|
||||
if (master->configs_attached)
|
||||
return 0;
|
||||
|
||||
list_for_each_entry(sc, &master->configs, list) {
|
||||
if (ec_slave_config_attach(sc))
|
||||
errors = 1;
|
||||
}
|
||||
|
||||
if (!remainder[0]) {
|
||||
if (alias_requested) { // alias addressing
|
||||
return alias_slave;
|
||||
}
|
||||
else { // position addressing
|
||||
list_for_each_entry(slave, &master->slaves, list) {
|
||||
if (slave->ring_position == first) return slave;
|
||||
}
|
||||
EC_ERR("Slave index out of range!\n");
|
||||
goto out_invalid;
|
||||
}
|
||||
}
|
||||
else if (alias_requested && remainder[0] == ':') { // field addressing
|
||||
struct list_head *list;
|
||||
remainder++;
|
||||
second = simple_strtoul(remainder, &remainder2, 0);
|
||||
|
||||
if (remainder2 == remainder || remainder2[0])
|
||||
goto out_invalid;
|
||||
|
||||
list = &alias_slave->list;
|
||||
while (second--) {
|
||||
list = list->next;
|
||||
if (list == &master->slaves) { // last slave exceeded
|
||||
EC_ERR("Slave index out of range!\n");
|
||||
goto out_invalid;
|
||||
}
|
||||
}
|
||||
return list_entry(list, ec_slave_t, list);
|
||||
}
|
||||
|
||||
out_invalid:
|
||||
EC_ERR("Invalid slave address string \"%s\"!\n", original);
|
||||
return NULL;
|
||||
master->configs_attached = !errors;
|
||||
return errors ? -1 : 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Realtime interface
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
Creates a domain.
|
||||
\return pointer to new domain on success, else NULL
|
||||
\ingroup RealtimeInterface
|
||||
*/
|
||||
|
||||
ec_domain_t *ecrt_master_create_domain(ec_master_t *master /**< master */)
|
||||
{
|
||||
ec_domain_t *domain, *last_domain;
|
||||
@@ -1364,25 +1329,16 @@ ec_domain_t *ecrt_master_create_domain(ec_master_t *master /**< master */)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Configures all slaves and leads them to the OP state.
|
||||
Does the complete configuration and activation for all slaves. Sets sync
|
||||
managers and FMMUs, and does the appropriate transitions, until the slave
|
||||
is operational.
|
||||
\return 0 in case of success, else < 0
|
||||
\ingroup RealtimeInterface
|
||||
*/
|
||||
|
||||
int ecrt_master_activate(ec_master_t *master /**< EtherCAT master */)
|
||||
int ecrt_master_activate(ec_master_t *master)
|
||||
{
|
||||
uint32_t domain_offset;
|
||||
ec_domain_t *domain;
|
||||
|
||||
// allocate all domains
|
||||
// finish all domains
|
||||
domain_offset = 0;
|
||||
list_for_each_entry(domain, &master->domains, list) {
|
||||
if (ec_domain_alloc(domain, domain_offset)) {
|
||||
EC_ERR("Failed to allocate domain %X!\n", (u32) domain);
|
||||
if (ec_domain_finish(domain, domain_offset)) {
|
||||
EC_ERR("Failed to finish domain %X!\n", (u32) domain);
|
||||
return -1;
|
||||
}
|
||||
domain_offset += domain->data_size;
|
||||
@@ -1435,12 +1391,7 @@ int ecrt_master_activate(ec_master_t *master /**< EtherCAT master */)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Asynchronous sending of datagrams.
|
||||
\ingroup RealtimeInterface
|
||||
*/
|
||||
|
||||
void ecrt_master_send(ec_master_t *master /**< EtherCAT master */)
|
||||
void ecrt_master_send(ec_master_t *master)
|
||||
{
|
||||
ec_datagram_t *datagram, *n;
|
||||
|
||||
@@ -1468,12 +1419,7 @@ void ecrt_master_send(ec_master_t *master /**< EtherCAT master */)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Asynchronous receiving of datagrams.
|
||||
\ingroup RealtimeInterface
|
||||
*/
|
||||
|
||||
void ecrt_master_receive(ec_master_t *master /**< EtherCAT master */)
|
||||
void ecrt_master_receive(ec_master_t *master)
|
||||
{
|
||||
ec_datagram_t *datagram, *next;
|
||||
cycles_t cycles_timeout;
|
||||
@@ -1510,80 +1456,65 @@ void ecrt_master_receive(ec_master_t *master /**< EtherCAT master */)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Obtains a slave pointer by its bus address.
|
||||
* A valid slave pointer is only returned, if vendor ID and product code are
|
||||
* matching.
|
||||
* \return pointer to the slave on success, else NULL
|
||||
* \ingroup RealtimeInterface
|
||||
*/
|
||||
|
||||
ec_slave_t *ecrt_master_get_slave(
|
||||
const ec_master_t *master, /**< EtherCAT master */
|
||||
const char *address, /**< address string
|
||||
\see ec_master_parse_slave_address() */
|
||||
uint32_t vendor_id, /**< vendor ID */
|
||||
uint32_t product_code /**< product code */
|
||||
)
|
||||
ec_slave_config_t *ecrt_master_slave_config(ec_master_t *master,
|
||||
uint16_t alias, uint16_t position, uint32_t vendor_id,
|
||||
uint32_t product_code)
|
||||
{
|
||||
ec_slave_t *slave = ec_master_parse_slave_address(master, address);
|
||||
|
||||
if (!slave)
|
||||
return NULL;
|
||||
|
||||
return ec_slave_validate(slave, vendor_id, product_code) ? NULL : slave;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Obtains a slave pointer by its ring position.
|
||||
* A valid slave pointer is only returned, if vendor ID and product code are
|
||||
* matching.
|
||||
* \return pointer to the slave on success, else NULL
|
||||
* \ingroup RealtimeInterface
|
||||
*/
|
||||
|
||||
ec_slave_t *ecrt_master_get_slave_by_pos(
|
||||
const ec_master_t *master, /**< EtherCAT master */
|
||||
uint16_t ring_position, /**< ring position */
|
||||
uint32_t vendor_id, /**< vendor ID */
|
||||
uint32_t product_code /**< product code */
|
||||
)
|
||||
{
|
||||
ec_slave_t *slave;
|
||||
ec_slave_config_t *sc;
|
||||
unsigned int found = 0;
|
||||
|
||||
list_for_each_entry(slave, &master->slaves, list) {
|
||||
if (slave->ring_position == ring_position) {
|
||||
list_for_each_entry(sc, &master->configs, list) {
|
||||
if (sc->alias == alias && sc->position == position) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
EC_ERR("Slave index out of range!\n");
|
||||
return NULL;
|
||||
if (found) {
|
||||
if (master->debug_level) {
|
||||
EC_INFO("Using existing slave configuration for %u:%u\n",
|
||||
alias, position);
|
||||
}
|
||||
if (sc->vendor_id != vendor_id || sc->product_code != product_code) {
|
||||
EC_ERR("Slave type mismatch. Slave was configured as"
|
||||
" 0x%08X/0x%08X before. Now configuring with"
|
||||
" 0x%08X/0x%08X.\n", sc->vendor_id, sc->product_code,
|
||||
vendor_id, product_code);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
if (master->debug_level) {
|
||||
EC_INFO("Creating slave configuration for %u:%u,"
|
||||
" 0x%08X/0x%08X.\n", alias, position, vendor_id,
|
||||
product_code);
|
||||
}
|
||||
|
||||
if (!(sc = (ec_slave_config_t *) kmalloc(sizeof(ec_slave_config_t),
|
||||
GFP_KERNEL))) {
|
||||
EC_ERR("Failed to allocate memory for slave configuration.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ec_slave_config_init(sc, master, alias, position, vendor_id,
|
||||
product_code)) {
|
||||
EC_ERR("Failed to init slave configuration.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// try to find the addressed slave
|
||||
ec_slave_config_attach(sc);
|
||||
ec_slave_config_load_default_mapping(sc);
|
||||
|
||||
list_add_tail(&sc->list, &master->configs);
|
||||
}
|
||||
|
||||
return ec_slave_validate(slave, vendor_id, product_code) ? NULL : slave;
|
||||
return sc;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Sets the locking callbacks.
|
||||
The request_cb function must return zero, to allow another instance
|
||||
(the EoE process for example) to access the master. Non-zero means,
|
||||
that access is forbidden at this time.
|
||||
\ingroup RealtimeInterface
|
||||
*/
|
||||
|
||||
void ecrt_master_callbacks(ec_master_t *master, /**< EtherCAT master */
|
||||
int (*request_cb)(void *), /**< request lock CB */
|
||||
void (*release_cb)(void *), /**< release lock CB */
|
||||
void *cb_data /**< data parameter */
|
||||
)
|
||||
void ecrt_master_callbacks(ec_master_t *master, int (*request_cb)(void *),
|
||||
void (*release_cb)(void *), void *cb_data)
|
||||
{
|
||||
master->ext_request_cb = request_cb;
|
||||
master->ext_release_cb = release_cb;
|
||||
@@ -1592,19 +1523,13 @@ void ecrt_master_callbacks(ec_master_t *master, /**< EtherCAT master */
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Reads the current master status.
|
||||
*/
|
||||
|
||||
void ecrt_master_get_status(const ec_master_t *master, /**< EtherCAT master */
|
||||
ec_master_status_t *status /**< target status object */
|
||||
)
|
||||
void ecrt_master_state(const ec_master_t *master, ec_master_state_t *state)
|
||||
{
|
||||
status->bus_status =
|
||||
state->bus_state =
|
||||
(master->pdo_slaves_offline || master->frames_timed_out)
|
||||
? EC_BUS_FAILURE : EC_BUS_OK;
|
||||
status->bus_tainted = master->fsm.tainted;
|
||||
status->slaves_responding = master->fsm.slaves_responding;
|
||||
state->bus_tainted = master->fsm.tainted;
|
||||
state->slaves_responding = master->fsm.slaves_responding;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -1616,9 +1541,8 @@ EXPORT_SYMBOL(ecrt_master_activate);
|
||||
EXPORT_SYMBOL(ecrt_master_send);
|
||||
EXPORT_SYMBOL(ecrt_master_receive);
|
||||
EXPORT_SYMBOL(ecrt_master_callbacks);
|
||||
EXPORT_SYMBOL(ecrt_master_get_slave);
|
||||
EXPORT_SYMBOL(ecrt_master_get_slave_by_pos);
|
||||
EXPORT_SYMBOL(ecrt_master_get_status);
|
||||
EXPORT_SYMBOL(ecrt_master_slave_config);
|
||||
EXPORT_SYMBOL(ecrt_master_state);
|
||||
|
||||
/** \endcond */
|
||||
|
||||
|
||||
+14
-17
@@ -53,12 +53,9 @@
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
EtherCAT master mode.
|
||||
*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
/** EtherCAT master mode.
|
||||
*/
|
||||
typedef enum {
|
||||
EC_MASTER_MODE_ORPHANED,
|
||||
EC_MASTER_MODE_IDLE,
|
||||
EC_MASTER_MODE_OPERATION
|
||||
@@ -67,12 +64,9 @@ ec_master_mode_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Cyclic statistics.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/** Cyclic statistics.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned int timeouts; /**< datagram timeouts */
|
||||
unsigned int corrupted; /**< corrupted frames */
|
||||
unsigned int unmatched; /**< unmatched datagrams (received, but not
|
||||
@@ -83,11 +77,10 @@ ec_stats_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
EtherCAT master.
|
||||
Manages slaves, domains and IO.
|
||||
*/
|
||||
|
||||
/** EtherCAT master.
|
||||
*
|
||||
* Manages slaves, domains and IO.
|
||||
*/
|
||||
struct ec_master
|
||||
{
|
||||
struct kobject kobj; /**< kobject */
|
||||
@@ -110,6 +103,9 @@ struct ec_master
|
||||
|
||||
struct list_head slaves; /**< list of slaves on the bus */
|
||||
unsigned int slave_count; /**< number of slaves on the bus */
|
||||
|
||||
struct list_head configs; /**< Bus configuration list. */
|
||||
unsigned int configs_attached; /**< Slave configurations were attached. */
|
||||
|
||||
ec_request_state_t scan_state; /**< current scanning state */
|
||||
unsigned int allow_scan; /**< non-zero, if slave scanning is allowed */
|
||||
@@ -196,6 +192,7 @@ void ec_master_receive_datagrams(ec_master_t *, const uint8_t *, size_t);
|
||||
void ec_master_queue_datagram(ec_master_t *, ec_datagram_t *);
|
||||
|
||||
// misc.
|
||||
int ec_master_attach_slave_configs(ec_master_t *);
|
||||
void ec_master_output_stats(ec_master_t *);
|
||||
#ifdef EC_EOE
|
||||
void ec_master_clear_eoe_handlers(ec_master_t *);
|
||||
|
||||
+13
-33
@@ -31,10 +31,9 @@
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
\file
|
||||
EtherCAT master driver module.
|
||||
*/
|
||||
/** \file
|
||||
* EtherCAT master driver module.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@@ -49,7 +48,7 @@
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#define MAX_MASTERS 5 /**< maximum number of masters */
|
||||
#define MAX_MASTERS 5 /**< Maximum number of masters. */
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@@ -541,28 +540,7 @@ void ecdev_close(ec_device_t *device /**< EtherCAT device */)
|
||||
* Realtime interface
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Returns the version magic of the realtime interface.
|
||||
* \return ECRT version magic.
|
||||
* \ingroup RealtimeInterface
|
||||
*/
|
||||
|
||||
unsigned int ecrt_version_magic(void)
|
||||
{
|
||||
return ECRT_VERSION_MAGIC;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Reserves an EtherCAT master for realtime operation.
|
||||
\return pointer to reserved master, or NULL on error
|
||||
\ingroup RealtimeInterface
|
||||
*/
|
||||
|
||||
ec_master_t *ecrt_request_master(unsigned int master_index
|
||||
/**< master index */
|
||||
)
|
||||
ec_master_t *ecrt_request_master(unsigned int master_index)
|
||||
{
|
||||
ec_master_t *master;
|
||||
|
||||
@@ -622,12 +600,7 @@ ec_master_t *ecrt_request_master(unsigned int master_index
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Releases a reserved EtherCAT master.
|
||||
\ingroup RealtimeInterface
|
||||
*/
|
||||
|
||||
void ecrt_release_master(ec_master_t *master /**< EtherCAT master */)
|
||||
void ecrt_release_master(ec_master_t *master)
|
||||
{
|
||||
EC_INFO("Releasing master %u...\n", master->index);
|
||||
|
||||
@@ -646,6 +619,13 @@ void ecrt_release_master(ec_master_t *master /**< EtherCAT master */)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
unsigned int ecrt_version_magic(void)
|
||||
{
|
||||
return ECRT_VERSION_MAGIC;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** \cond */
|
||||
|
||||
module_init(ec_init_module);
|
||||
|
||||
+154
-24
@@ -44,66 +44,196 @@
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* PDO constructor.
|
||||
*/
|
||||
void ec_pdo_clear_entries(ec_pdo_t *);
|
||||
|
||||
void ec_pdo_init(ec_pdo_t *pdo /**< EtherCAT PDO */)
|
||||
/*****************************************************************************/
|
||||
|
||||
/** PDO constructor.
|
||||
*/
|
||||
void ec_pdo_init(
|
||||
ec_pdo_t *pdo /**< EtherCAT PDO */
|
||||
)
|
||||
{
|
||||
pdo->sync_index = -1; // not assigned
|
||||
pdo->name = NULL;
|
||||
INIT_LIST_HEAD(&pdo->entries);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* PDO destructor.
|
||||
/** Pdo copy constructor.
|
||||
*/
|
||||
int ec_pdo_init_copy(ec_pdo_t *pdo, const ec_pdo_t *other_pdo)
|
||||
{
|
||||
pdo->dir = other_pdo->dir;
|
||||
pdo->index = other_pdo->index;
|
||||
pdo->sync_index = other_pdo->sync_index;
|
||||
pdo->name = NULL;
|
||||
INIT_LIST_HEAD(&pdo->entries);
|
||||
|
||||
if (ec_pdo_set_name(pdo, other_pdo->name))
|
||||
goto out_return;
|
||||
|
||||
if (ec_pdo_copy_entries(pdo, other_pdo))
|
||||
goto out_clear;
|
||||
|
||||
return 0;
|
||||
|
||||
out_clear:
|
||||
ec_pdo_clear(pdo);
|
||||
out_return:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** PDO destructor.
|
||||
*/
|
||||
void ec_pdo_clear(ec_pdo_t *pdo /**< EtherCAT PDO */)
|
||||
{
|
||||
if (pdo->name)
|
||||
kfree(pdo->name);
|
||||
|
||||
ec_pdo_clear_entries(pdo);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Clear Pdo entry list.
|
||||
*/
|
||||
void ec_pdo_clear_entries(ec_pdo_t *pdo /**< EtherCAT PDO */)
|
||||
{
|
||||
ec_pdo_entry_t *entry, *next;
|
||||
|
||||
// free all PDO entries
|
||||
list_for_each_entry_safe(entry, next, &pdo->entries, list) {
|
||||
list_del(&entry->list);
|
||||
ec_pdo_entry_clear(entry);
|
||||
kfree(entry);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Makes a deep copy of a PDO.
|
||||
/** Set Pdo name.
|
||||
*/
|
||||
|
||||
int ec_pdo_copy(ec_pdo_t *pdo, const ec_pdo_t *other_pdo)
|
||||
int ec_pdo_set_name(
|
||||
ec_pdo_t *pdo, /**< Pdo. */
|
||||
const char *name /**< New name. */
|
||||
)
|
||||
{
|
||||
ec_pdo_entry_t *entry, *other_entry, *next;
|
||||
unsigned int len;
|
||||
|
||||
// make flat copy
|
||||
*pdo = *other_pdo;
|
||||
if (pdo->name)
|
||||
kfree(pdo->name);
|
||||
|
||||
INIT_LIST_HEAD(&pdo->entries);
|
||||
list_for_each_entry(other_entry, &other_pdo->entries, list) {
|
||||
if (name && (len = strlen(name))) {
|
||||
if (!(pdo->name = (char *) kmalloc(len + 1, GFP_KERNEL))) {
|
||||
EC_ERR("Failed to allocate PDO name.\n");
|
||||
return -1;
|
||||
}
|
||||
memcpy(pdo->name, name, len + 1);
|
||||
} else {
|
||||
pdo->name = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Copy Pdo entries from another Pdo.
|
||||
*/
|
||||
int ec_pdo_copy_entries(ec_pdo_t *pdo, const ec_pdo_t *other)
|
||||
{
|
||||
ec_pdo_entry_t *entry, *other_entry;
|
||||
|
||||
ec_pdo_clear_entries(pdo);
|
||||
|
||||
list_for_each_entry(other_entry, &other->entries, list) {
|
||||
if (!(entry = (ec_pdo_entry_t *)
|
||||
kmalloc(sizeof(ec_pdo_entry_t), GFP_KERNEL))) {
|
||||
EC_ERR("Failed to allocate memory for PDO entry copy.\n");
|
||||
goto out_free;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ec_pdo_entry_init_copy(entry, other_entry)) {
|
||||
kfree(entry);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*entry = *other_entry; // flat copy is sufficient
|
||||
list_add_tail(&entry->list, &pdo->entries);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_free:
|
||||
list_for_each_entry_safe(entry, next, &pdo->entries, list) {
|
||||
list_del(&entry->list);
|
||||
kfree(entry);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Pdo entry constructor.
|
||||
*/
|
||||
void ec_pdo_entry_init(
|
||||
ec_pdo_entry_t *entry /**< Pdo entry. */
|
||||
)
|
||||
{
|
||||
entry->name = NULL;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Pdo entry copy constructor.
|
||||
*/
|
||||
int ec_pdo_entry_init_copy(
|
||||
ec_pdo_entry_t *entry, /**< Pdo entry. */
|
||||
const ec_pdo_entry_t *other /**< Pdo entry to copy from. */
|
||||
)
|
||||
{
|
||||
entry->index = other->index;
|
||||
entry->subindex = other->subindex;
|
||||
entry->name = NULL;
|
||||
entry->bit_length = other->bit_length;
|
||||
|
||||
if (ec_pdo_entry_set_name(entry, other->name))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Pdo entry destructor.
|
||||
*/
|
||||
void ec_pdo_entry_clear(ec_pdo_entry_t *entry /**< Pdo entry. */)
|
||||
{
|
||||
if (entry->name)
|
||||
kfree(entry->name);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Set Pdo entry name.
|
||||
*/
|
||||
int ec_pdo_entry_set_name(
|
||||
ec_pdo_entry_t *entry, /**< Pdo entry. */
|
||||
const char *name /**< New name. */
|
||||
)
|
||||
{
|
||||
unsigned int len;
|
||||
|
||||
if (entry->name)
|
||||
kfree(entry->name);
|
||||
|
||||
if (name && (len = strlen(name))) {
|
||||
if (!(entry->name = (char *) kmalloc(len + 1, GFP_KERNEL))) {
|
||||
EC_ERR("Failed to allocate PDO entry name.\n");
|
||||
return -1;
|
||||
}
|
||||
memcpy(entry->name, name, len + 1);
|
||||
} else {
|
||||
entry->name = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
+22
-34
@@ -43,59 +43,47 @@
|
||||
|
||||
#include <linux/list.h>
|
||||
|
||||
#include "../include/ecrt.h"
|
||||
|
||||
#include "globals.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* PDO type.
|
||||
/** PDO description.
|
||||
*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
EC_RX_PDO, /**< Reveive PDO */
|
||||
EC_TX_PDO /**< Transmit PDO */
|
||||
}
|
||||
ec_pdo_type_t;
|
||||
typedef struct {
|
||||
struct list_head list; /**< List item. */
|
||||
ec_direction_t dir; /**< PDO direction. */
|
||||
uint16_t index; /**< PDO index. */
|
||||
int8_t sync_index; /**< Assigned sync manager. */
|
||||
char *name; /**< PDO name. */
|
||||
struct list_head entries; /**< List of PDO entries. */
|
||||
} ec_pdo_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* PDO description.
|
||||
/** PDO entry description.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct list_head list; /**< list item */
|
||||
ec_pdo_type_t type; /**< PDO type */
|
||||
uint16_t index; /**< PDO index */
|
||||
int8_t sync_index; /**< assigned sync manager */
|
||||
char *name; /**< PDO name */
|
||||
struct list_head entries; /**< entry list */
|
||||
}
|
||||
ec_pdo_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* PDO entry description.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
struct list_head list; /**< list item */
|
||||
uint16_t index; /**< PDO entry index */
|
||||
uint8_t subindex; /**< PDO entry subindex */
|
||||
char *name; /**< entry name */
|
||||
uint8_t bit_length; /**< entry length in bit */
|
||||
}
|
||||
ec_pdo_entry_t;
|
||||
} ec_pdo_entry_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_pdo_init(ec_pdo_t *);
|
||||
int ec_pdo_init_copy(ec_pdo_t *, const ec_pdo_t *);
|
||||
void ec_pdo_clear(ec_pdo_t *);
|
||||
int ec_pdo_copy(ec_pdo_t *, const ec_pdo_t *);
|
||||
int ec_pdo_set_name(ec_pdo_t *, const char *);
|
||||
int ec_pdo_copy_entries(ec_pdo_t *, const ec_pdo_t *);
|
||||
|
||||
void ec_pdo_entry_init(ec_pdo_entry_t *);
|
||||
int ec_pdo_entry_init_copy(ec_pdo_entry_t *, const ec_pdo_entry_t *);
|
||||
void ec_pdo_entry_clear(ec_pdo_entry_t *);
|
||||
int ec_pdo_entry_set_name(ec_pdo_entry_t *, const char *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
@@ -0,0 +1,319 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
* The IgH EtherCAT Master is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* The IgH EtherCAT Master is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the IgH EtherCAT Master; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* The right to use EtherCAT Technology is granted and comes free of
|
||||
* charge under condition of compatibility of product made by
|
||||
* Licensee. People intending to distribute/sell products based on the
|
||||
* code, have to sign an agreement to guarantee that products using
|
||||
* software based on IgH EtherCAT master stay compatible with the actual
|
||||
* EtherCAT specification (which are released themselves as an open
|
||||
* standard) as the (only) precondition to have the right to use EtherCAT
|
||||
* Technology, IP and trade marks.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
\file
|
||||
EtherCAT Pdo mapping methods.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "globals.h"
|
||||
#include "pdo.h"
|
||||
#include "slave_config.h"
|
||||
#include "master.h"
|
||||
|
||||
#include "pdo_mapping.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Pdo mapping constructor.
|
||||
*/
|
||||
void ec_pdo_mapping_init(
|
||||
ec_pdo_mapping_t *pm /**< Pdo mapping. */
|
||||
)
|
||||
{
|
||||
INIT_LIST_HEAD(&pm->pdos);
|
||||
pm->default_mapping = 1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Pdo mapping destructor.
|
||||
*/
|
||||
void ec_pdo_mapping_clear(ec_pdo_mapping_t *pm /**< Pdo mapping. */)
|
||||
{
|
||||
ec_pdo_mapping_clear_pdos(pm);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Clears the list of mapped Pdos.
|
||||
*/
|
||||
void ec_pdo_mapping_clear_pdos(ec_pdo_mapping_t *pm /**< Pdo mapping. */)
|
||||
{
|
||||
ec_pdo_t *pdo, *next;
|
||||
|
||||
list_for_each_entry_safe(pdo, next, &pm->pdos, list) {
|
||||
list_del_init(&pdo->list);
|
||||
ec_pdo_clear(pdo);
|
||||
kfree(pdo);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Calculates the total size of the mapped PDO entries.
|
||||
*
|
||||
* \retval Data size in byte.
|
||||
*/
|
||||
uint16_t ec_pdo_mapping_total_size(
|
||||
const ec_pdo_mapping_t *pm /**< Pdo mapping. */
|
||||
)
|
||||
{
|
||||
unsigned int bit_size;
|
||||
const ec_pdo_t *pdo;
|
||||
const ec_pdo_entry_t *pdo_entry;
|
||||
uint16_t byte_size;
|
||||
|
||||
bit_size = 0;
|
||||
list_for_each_entry(pdo, &pm->pdos, list) {
|
||||
list_for_each_entry(pdo_entry, &pdo->entries, list) {
|
||||
bit_size += pdo_entry->bit_length;
|
||||
}
|
||||
}
|
||||
|
||||
if (bit_size % 8) // round up to full bytes
|
||||
byte_size = bit_size / 8 + 1;
|
||||
else
|
||||
byte_size = bit_size / 8;
|
||||
|
||||
return byte_size;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Adds a Pdo to the mapping.
|
||||
*
|
||||
* \return 0 on success, else < 0
|
||||
*/
|
||||
int ec_pdo_mapping_add_pdo(
|
||||
ec_pdo_mapping_t *pm, /**< Pdo mapping. */
|
||||
const ec_pdo_t *pdo /**< PDO to add. */
|
||||
)
|
||||
{
|
||||
ec_pdo_t *mapped_pdo;
|
||||
|
||||
// PDO already mapped?
|
||||
list_for_each_entry(mapped_pdo, &pm->pdos, list) {
|
||||
if (mapped_pdo->index != pdo->index) continue;
|
||||
EC_ERR("PDO 0x%04X is already mapped!\n", pdo->index);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(mapped_pdo = kmalloc(sizeof(ec_pdo_t), GFP_KERNEL))) {
|
||||
EC_ERR("Failed to allocate memory for PDO mapping.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ec_pdo_init_copy(mapped_pdo, pdo)) {
|
||||
kfree(mapped_pdo);
|
||||
return -1;
|
||||
}
|
||||
|
||||
list_add_tail(&mapped_pdo->list, &pm->pdos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Add a Pdo to the mapping.
|
||||
*
|
||||
* The first call of this method will clear the default mapping.
|
||||
*
|
||||
* \retval 0 Success.
|
||||
* \retval -1 Error.
|
||||
*/
|
||||
int ec_pdo_mapping_add_pdo_info(
|
||||
ec_pdo_mapping_t *pm, /**< Pdo mapping. */
|
||||
const ec_pdo_info_t *pdo_info, /**< Pdo information. */
|
||||
const ec_slave_config_t *config /**< Slave configuration, to load
|
||||
default entries. */
|
||||
)
|
||||
{
|
||||
unsigned int i;
|
||||
ec_pdo_t *pdo;
|
||||
ec_pdo_entry_t *entry;
|
||||
const ec_pdo_entry_info_t *entry_info;
|
||||
|
||||
if (pm->default_mapping) {
|
||||
pm->default_mapping = 0;
|
||||
ec_pdo_mapping_clear_pdos(pm);
|
||||
}
|
||||
|
||||
if (!(pdo = (ec_pdo_t *) kmalloc(sizeof(ec_pdo_t), GFP_KERNEL))) {
|
||||
EC_ERR("Failed to allocate memory for Pdo.\n");
|
||||
goto out_return;
|
||||
}
|
||||
|
||||
ec_pdo_init(pdo);
|
||||
pdo->dir = pdo_info->dir;
|
||||
pdo->index = pdo_info->index;
|
||||
|
||||
if (config->master->debug_level)
|
||||
EC_INFO("Adding Pdo 0x%04X to mapping.\n", pdo->index);
|
||||
|
||||
if (pdo_info->n_entries) { // Pdo configuration provided
|
||||
if (config->master->debug_level)
|
||||
EC_INFO(" Pdo configuration provided.\n");
|
||||
|
||||
for (i = 0; i < pdo_info->n_entries; i++) {
|
||||
entry_info = &pdo_info->entries[i];
|
||||
|
||||
if (!(entry = kmalloc(sizeof(ec_pdo_entry_t), GFP_KERNEL))) {
|
||||
EC_ERR("Failed to allocate memory for PDO entry.\n");
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
ec_pdo_entry_init(entry);
|
||||
entry->index = entry_info->index;
|
||||
entry->subindex = entry_info->subindex;
|
||||
entry->bit_length = entry_info->bit_length;
|
||||
list_add_tail(&entry->list, &pdo->entries);
|
||||
}
|
||||
} else { // use default Pdo configuration
|
||||
if (config->master->debug_level)
|
||||
EC_INFO(" Using default Pdo configuration.\n");
|
||||
|
||||
if (config->slave) {
|
||||
ec_sync_t *sync;
|
||||
ec_pdo_t *default_pdo;
|
||||
|
||||
if ((sync = ec_slave_get_pdo_sync(config->slave, pdo->dir))) {
|
||||
list_for_each_entry(default_pdo, &sync->mapping.pdos, list) {
|
||||
if (default_pdo->index != pdo->index)
|
||||
continue;
|
||||
if (config->master->debug_level)
|
||||
EC_INFO(" Found Pdo name \"%s\".\n",
|
||||
default_pdo->name);
|
||||
// try to take Pdo name from mapped one
|
||||
if (ec_pdo_set_name(pdo, default_pdo->name))
|
||||
goto out_free;
|
||||
// copy entries (= default Pdo configuration)
|
||||
if (ec_pdo_copy_entries(pdo, default_pdo))
|
||||
goto out_free;
|
||||
if (config->master->debug_level) {
|
||||
const ec_pdo_entry_t *entry;
|
||||
list_for_each_entry(entry, &pdo->entries, list) {
|
||||
EC_INFO(" Entry 0x%04X:%u.\n",
|
||||
entry->index, entry->subindex);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
EC_WARN("Slave %u does not provide a default Pdo"
|
||||
" configuration!\n", config->slave->ring_position);
|
||||
}
|
||||
} else {
|
||||
EC_WARN("Failed to load default Pdo configuration for %u:%u:"
|
||||
" Slave not found.\n", config->alias, config->position);
|
||||
}
|
||||
}
|
||||
|
||||
list_add_tail(&pdo->list, &pm->pdos);
|
||||
return 0;
|
||||
|
||||
out_free:
|
||||
ec_pdo_clear(pdo);
|
||||
kfree(pdo);
|
||||
out_return:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Makes a deep copy of another Pdo mapping.
|
||||
*
|
||||
* \return 0 on success, else < 0
|
||||
*/
|
||||
int ec_pdo_mapping_copy(
|
||||
ec_pdo_mapping_t *pm, /**< Pdo mapping. */
|
||||
const ec_pdo_mapping_t *other /**< PDO mapping to copy from. */
|
||||
)
|
||||
{
|
||||
ec_pdo_t *other_pdo;
|
||||
|
||||
ec_pdo_mapping_clear_pdos(pm);
|
||||
|
||||
// PDO already mapped?
|
||||
list_for_each_entry(other_pdo, &other->pdos, list) {
|
||||
if (ec_pdo_mapping_add_pdo(pm, other_pdo))
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Compares two Pdo mappings.
|
||||
*
|
||||
* Only the mapping is compared, not the Pdo entries (i. e. the Pdo
|
||||
* configuration).
|
||||
*
|
||||
* \retval 1 The given Pdo mappings are equal.
|
||||
* \retval 0 The given Pdo mappings differ.
|
||||
*/
|
||||
int ec_pdo_mapping_equal(
|
||||
const ec_pdo_mapping_t *pm1, /**< First mapping. */
|
||||
const ec_pdo_mapping_t *pm2 /**< Second mapping. */
|
||||
)
|
||||
{
|
||||
const struct list_head *h1, *h2, *l1, *l2;
|
||||
const ec_pdo_t *p1, *p2;
|
||||
|
||||
h1 = l1 = &pm1->pdos;
|
||||
h2 = l2 = &pm2->pdos;
|
||||
|
||||
while (1) {
|
||||
l1 = l1->next;
|
||||
l2 = l2->next;
|
||||
|
||||
if ((l1 == h1) ^ (l2 == h2)) // unequal lengths
|
||||
return 0;
|
||||
if (l1 == h1 && l2 == h2) // both finished
|
||||
break;
|
||||
|
||||
p1 = list_entry(l1, ec_pdo_t, list);
|
||||
p2 = list_entry(l2, ec_pdo_t, list);
|
||||
|
||||
if (p1->index != p2->index)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -0,0 +1,77 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
* The IgH EtherCAT Master is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* The IgH EtherCAT Master is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the IgH EtherCAT Master; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* The right to use EtherCAT Technology is granted and comes free of
|
||||
* charge under condition of compatibility of product made by
|
||||
* Licensee. People intending to distribute/sell products based on the
|
||||
* code, have to sign an agreement to guarantee that products using
|
||||
* software based on IgH EtherCAT master stay compatible with the actual
|
||||
* EtherCAT specification (which are released themselves as an open
|
||||
* standard) as the (only) precondition to have the right to use EtherCAT
|
||||
* Technology, IP and trade marks.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
\file
|
||||
EtherCAT Pdo mapping structure.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef _EC_PDO_MAPPING_H_
|
||||
#define _EC_PDO_MAPPING_H_
|
||||
|
||||
#include <linux/list.h>
|
||||
|
||||
#include "../include/ecrt.h"
|
||||
|
||||
#include "globals.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** EtherCAT PDO mapping.
|
||||
*/
|
||||
typedef struct {
|
||||
struct list_head pdos; /**< List of Pdos. */
|
||||
unsigned int default_mapping; /**< This is the default mapping. */
|
||||
} ec_pdo_mapping_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_pdo_mapping_init(ec_pdo_mapping_t *);
|
||||
void ec_pdo_mapping_clear(ec_pdo_mapping_t *);
|
||||
|
||||
void ec_pdo_mapping_clear_pdos(ec_pdo_mapping_t *);
|
||||
|
||||
int ec_pdo_mapping_add_pdo(ec_pdo_mapping_t *, const ec_pdo_t *);
|
||||
int ec_pdo_mapping_add_pdo_info(ec_pdo_mapping_t *, const ec_pdo_info_t *,
|
||||
const ec_slave_config_t *);
|
||||
|
||||
int ec_pdo_mapping_copy(ec_pdo_mapping_t *, const ec_pdo_mapping_t *);
|
||||
|
||||
uint16_t ec_pdo_mapping_total_size(const ec_pdo_mapping_t *);
|
||||
int ec_pdo_mapping_equal(const ec_pdo_mapping_t *, const ec_pdo_mapping_t *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#endif
|
||||
+31
-361
File diff suppressed because it is too large
Load Diff
+17
-43
@@ -50,21 +50,12 @@
|
||||
#include "datagram.h"
|
||||
#include "pdo.h"
|
||||
#include "sync.h"
|
||||
#include "fmmu.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** maximum number of FMMUs per slave */
|
||||
#define EC_MAX_FMMUS 16
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* State of an EtherCAT slave.
|
||||
/** State of an EtherCAT slave.
|
||||
*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
typedef enum {
|
||||
EC_SLAVE_STATE_UNKNOWN = 0x00,
|
||||
/**< unknown state */
|
||||
EC_SLAVE_STATE_INIT = 0x01,
|
||||
@@ -77,29 +68,22 @@ typedef enum
|
||||
/**< OP (mailbox communication and input/output update) */
|
||||
EC_SLAVE_STATE_ACK_ERR = 0x10
|
||||
/**< Acknowledge/Error bit (no actual state) */
|
||||
}
|
||||
ec_slave_state_t;
|
||||
} ec_slave_state_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* EtherCAT slave online state.
|
||||
/** EtherCAT slave online state.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
EC_SLAVE_OFFLINE,
|
||||
EC_SLAVE_ONLINE
|
||||
}
|
||||
ec_slave_online_state_t;
|
||||
} ec_slave_online_state_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Supported mailbox protocols.
|
||||
/** Supported mailbox protocols.
|
||||
*/
|
||||
|
||||
enum
|
||||
{
|
||||
enum {
|
||||
EC_MBOX_AOE = 0x01, /**< ADS-over-EtherCAT */
|
||||
EC_MBOX_EOE = 0x02, /**< Ethernet-over-EtherCAT */
|
||||
EC_MBOX_COE = 0x04, /**< CANopen-over-EtherCAT */
|
||||
@@ -110,27 +94,26 @@ enum
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* EtherCAT slave.
|
||||
/** EtherCAT slave.
|
||||
*/
|
||||
|
||||
struct ec_slave
|
||||
{
|
||||
struct list_head list; /**< list item */
|
||||
struct kobject kobj; /**< kobject */
|
||||
ec_master_t *master; /**< master owning the slave */
|
||||
|
||||
ec_slave_state_t requested_state; /**< requested application state */
|
||||
ec_slave_state_t current_state; /**< current application state */
|
||||
ec_slave_online_state_t online_state; /**< online state */
|
||||
unsigned int self_configured; /**< slave was configured by this master */
|
||||
unsigned int error_flag; /**< stop processing after an error */
|
||||
unsigned int pdos_registered; /**< non-zero, if PDOs were registered */
|
||||
|
||||
// addresses
|
||||
uint16_t ring_position; /**< ring position */
|
||||
uint16_t station_address; /**< configured station address */
|
||||
|
||||
// configuration
|
||||
ec_slave_config_t *config; /**< Current configuration. */
|
||||
ec_slave_state_t requested_state; /**< Requested application state. */
|
||||
ec_slave_state_t current_state; /**< Current application state. */
|
||||
ec_slave_online_state_t online_state; /**< online state */
|
||||
unsigned int self_configured; /**< Slave was configured by this master. */
|
||||
unsigned int error_flag; /**< Stop processing after an error. */
|
||||
|
||||
// base data
|
||||
uint8_t base_type; /**< slave type */
|
||||
uint8_t base_revision; /**< revision */
|
||||
@@ -169,12 +152,8 @@ struct ec_slave
|
||||
char *sii_name; /**< slave name acc. to EEPROM */
|
||||
int16_t sii_current_on_ebus; /**< power consumption */
|
||||
|
||||
ec_fmmu_t fmmus[EC_MAX_FMMUS]; /**< FMMU configurations */
|
||||
uint8_t fmmu_count; /**< number of FMMUs used */
|
||||
|
||||
struct kobject sdo_kobj; /**< kobject for SDOs */
|
||||
struct list_head sdo_dictionary; /**< SDO dictionary list */
|
||||
struct list_head sdo_confs; /**< list of SDO configurations */
|
||||
uint8_t sdo_dictionary_fetched; /**< dictionary has been fetched */
|
||||
unsigned long jiffies_preop; /**< time, the slave went to PREOP */
|
||||
|
||||
@@ -187,11 +166,6 @@ struct ec_slave
|
||||
int ec_slave_init(ec_slave_t *, ec_master_t *, uint16_t, uint16_t);
|
||||
void ec_slave_destroy(ec_slave_t *);
|
||||
|
||||
void ec_slave_reset(ec_slave_t *);
|
||||
|
||||
int ec_slave_prepare_fmmu(ec_slave_t *, const ec_domain_t *,
|
||||
const ec_sync_t *);
|
||||
|
||||
void ec_slave_request_state(ec_slave_t *, ec_slave_state_t);
|
||||
void ec_slave_set_state(ec_slave_t *, ec_slave_state_t);
|
||||
void ec_slave_set_online_state(ec_slave_t *, ec_slave_online_state_t);
|
||||
@@ -201,7 +175,7 @@ int ec_slave_fetch_sii_strings(ec_slave_t *, const uint8_t *, size_t);
|
||||
int ec_slave_fetch_sii_general(ec_slave_t *, const uint8_t *, size_t);
|
||||
int ec_slave_fetch_sii_syncs(ec_slave_t *, const uint8_t *, size_t);
|
||||
int ec_slave_fetch_sii_pdos(ec_slave_t *, const uint8_t *, size_t,
|
||||
ec_pdo_type_t);
|
||||
ec_direction_t);
|
||||
|
||||
// misc.
|
||||
ec_sync_t *ec_slave_get_pdo_sync(ec_slave_t *, ec_direction_t);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,96 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
* The IgH EtherCAT Master is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* The IgH EtherCAT Master is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the IgH EtherCAT Master; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* The right to use EtherCAT Technology is granted and comes free of
|
||||
* charge under condition of compatibility of product made by
|
||||
* Licensee. People intending to distribute/sell products based on the
|
||||
* code, have to sign an agreement to guarantee that products using
|
||||
* software based on IgH EtherCAT master stay compatible with the actual
|
||||
* EtherCAT specification (which are released themselves as an open
|
||||
* standard) as the (only) precondition to have the right to use EtherCAT
|
||||
* Technology, IP and trade marks.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
\file
|
||||
EtherCAT slave configuration structure.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef _EC_SLAVE_CONFIG_H_
|
||||
#define _EC_SLAVE_CONFIG_H_
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/kobject.h>
|
||||
|
||||
#include "../include/ecrt.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "slave.h"
|
||||
#include "fmmu_config.h"
|
||||
#include "pdo_mapping.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** EtherCAT slave configuration.
|
||||
*/
|
||||
struct ec_slave_config {
|
||||
struct list_head list; /**< List item. */
|
||||
struct kobject kobj; /**< kobject. */
|
||||
ec_master_t *master; /**< Master owning the slave configuration. */
|
||||
|
||||
uint16_t alias; /**< Slave alias. */
|
||||
uint16_t position; /**< Index after alias. If alias is zero, this is the
|
||||
ring position. */
|
||||
uint32_t vendor_id; /**< Slave vendor ID. */
|
||||
uint32_t product_code; /**< Slave product code. */
|
||||
|
||||
ec_slave_t *slave; /**< Slave pointer. This is \a NULL, if the slave is
|
||||
offline. */
|
||||
|
||||
ec_pdo_mapping_t mapping[2]; /**< Output and input PDO mapping. */
|
||||
|
||||
struct list_head sdo_configs; /**< SDO configurations. */
|
||||
|
||||
ec_fmmu_config_t fmmu_configs[EC_MAX_FMMUS]; /**< FMMU configurations. */
|
||||
uint8_t used_fmmus; /**< Number of FMMUs used. */
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int ec_slave_config_init(ec_slave_config_t *, ec_master_t *, uint16_t,
|
||||
uint16_t, uint32_t, uint32_t);
|
||||
void ec_slave_config_destroy(ec_slave_config_t *);
|
||||
|
||||
int ec_slave_config_reg_pdo_entry(ec_slave_config_t *, ec_domain_t *,
|
||||
uint16_t, uint8_t);
|
||||
|
||||
int ec_slave_config_attach(ec_slave_config_t *);
|
||||
void ec_slave_config_detach(ec_slave_config_t *);
|
||||
|
||||
void ec_slave_config_load_default_mapping(ec_slave_config_t *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#endif
|
||||
+32
-120
@@ -31,10 +31,9 @@
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
\file
|
||||
EtherCAT sync manager methods.
|
||||
*/
|
||||
/** \file
|
||||
* EtherCAT sync manager methods.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@@ -46,93 +45,52 @@
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
/** Constructor.
|
||||
*/
|
||||
|
||||
void ec_sync_init(
|
||||
ec_sync_t *sync, /**< EtherCAT sync manager */
|
||||
ec_slave_t *slave, /**< EtherCAT slave */
|
||||
unsigned int index /**< sync manager index */
|
||||
ec_sync_t *sync, /**< EtherCAT sync manager. */
|
||||
ec_slave_t *slave, /**< EtherCAT slave. */
|
||||
unsigned int index /**< Sync manager index. */
|
||||
)
|
||||
{
|
||||
sync->slave = slave;
|
||||
sync->index = index;
|
||||
|
||||
sync->est_length = 0;
|
||||
INIT_LIST_HEAD(&sync->pdos);
|
||||
sync->alt_mapping = 0;
|
||||
ec_pdo_mapping_init(&sync->mapping);
|
||||
sync->mapping_source = EC_SYNC_MAPPING_NONE;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
/** Destructor.
|
||||
*/
|
||||
|
||||
void ec_sync_clear(
|
||||
ec_sync_t *sync /**< EtherCAT sync manager */
|
||||
ec_sync_t *sync /**< EtherCAT sync manager. */
|
||||
)
|
||||
{
|
||||
ec_sync_clear_pdos(sync);
|
||||
ec_pdo_mapping_clear(&sync->mapping);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Calculates the size of a sync manager by evaluating PDO sizes.
|
||||
* \return sync manager size
|
||||
/** Initializes a sync manager configuration page with EEPROM data.
|
||||
*
|
||||
* The referenced memory (\a data) must be at least \a EC_SYNC_SIZE bytes.
|
||||
*/
|
||||
|
||||
uint16_t ec_sync_size(
|
||||
const ec_sync_t *sync /**< sync manager */
|
||||
)
|
||||
{
|
||||
const ec_pdo_t *pdo;
|
||||
const ec_pdo_entry_t *pdo_entry;
|
||||
unsigned int bit_size, byte_size;
|
||||
|
||||
if (sync->length) return sync->length;
|
||||
if (sync->est_length) return sync->est_length;
|
||||
|
||||
bit_size = 0;
|
||||
list_for_each_entry(pdo, &sync->pdos, list) {
|
||||
list_for_each_entry(pdo_entry, &pdo->entries, list) {
|
||||
bit_size += pdo_entry->bit_length;
|
||||
}
|
||||
}
|
||||
|
||||
if (bit_size % 8) // round up to full bytes
|
||||
byte_size = bit_size / 8 + 1;
|
||||
else
|
||||
byte_size = bit_size / 8;
|
||||
|
||||
return byte_size;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Initializes a sync manager configuration page with EEPROM data.
|
||||
The referenced memory (\a data) must be at least EC_SYNC_SIZE bytes.
|
||||
*/
|
||||
|
||||
void ec_sync_config(
|
||||
const ec_sync_t *sync, /**< sync manager */
|
||||
uint8_t *data /**> configuration memory */
|
||||
const ec_sync_t *sync, /**< Sync manager. */
|
||||
uint16_t data_size, /**< Data size. */
|
||||
uint8_t *data /**> Configuration memory. */
|
||||
)
|
||||
{
|
||||
size_t sync_size = ec_sync_size(sync);
|
||||
|
||||
if (sync->slave->master->debug_level) {
|
||||
EC_DBG("SM%i: Addr 0x%04X, Size %3i, Ctrl 0x%02X, En %i\n",
|
||||
sync->index, sync->physical_start_address,
|
||||
sync_size, sync->control_register, sync->enable);
|
||||
data_size, sync->control_register, sync->enable);
|
||||
}
|
||||
|
||||
EC_WRITE_U16(data, sync->physical_start_address);
|
||||
EC_WRITE_U16(data + 2, sync_size);
|
||||
EC_WRITE_U16(data + 2, data_size);
|
||||
EC_WRITE_U8 (data + 4, sync->control_register);
|
||||
EC_WRITE_U8 (data + 5, 0x00); // status byte (read only)
|
||||
EC_WRITE_U16(data + 6, sync->enable ? 0x0001 : 0x0000); // enable
|
||||
@@ -140,72 +98,26 @@ void ec_sync_config(
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Adds a PDO to the list of known mapped PDOs.
|
||||
/** Adds a PDO to the list of known mapped PDOs.
|
||||
*
|
||||
* \return 0 on success, else < 0
|
||||
*/
|
||||
|
||||
int ec_sync_add_pdo(
|
||||
ec_sync_t *sync, /**< EtherCAT sync manager */
|
||||
const ec_pdo_t *pdo /**< PDO to map */
|
||||
ec_sync_t *sync, /**< EtherCAT sync manager. */
|
||||
const ec_pdo_t *pdo /**< PDO to map. */
|
||||
)
|
||||
{
|
||||
ec_pdo_t *mapped_pdo;
|
||||
|
||||
// PDO already mapped?
|
||||
list_for_each_entry(mapped_pdo, &sync->pdos, list) {
|
||||
if (mapped_pdo->index != pdo->index) continue;
|
||||
EC_ERR("PDO 0x%04X is already mapped!\n", pdo->index);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(mapped_pdo = kmalloc(sizeof(ec_pdo_t), GFP_KERNEL))) {
|
||||
EC_ERR("Failed to allocate memory for PDO mapping.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ec_pdo_init(mapped_pdo);
|
||||
if (ec_pdo_copy(mapped_pdo, pdo)) {
|
||||
ec_pdo_clear(mapped_pdo);
|
||||
kfree(mapped_pdo);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// set appropriate sync manager index
|
||||
mapped_pdo->sync_index = sync->index;
|
||||
|
||||
list_add_tail(&mapped_pdo->list, &sync->pdos);
|
||||
return 0;
|
||||
return ec_pdo_mapping_add_pdo(&sync->mapping, pdo);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Clears the list of known mapped PDOs.
|
||||
/** Get direction covered by sync manager.
|
||||
*
|
||||
* \return Direction covered by the given sync manager.
|
||||
*/
|
||||
|
||||
void ec_sync_clear_pdos(
|
||||
ec_sync_t *sync /**< EtherCAT sync manager */
|
||||
)
|
||||
{
|
||||
ec_pdo_t *pdo, *next;
|
||||
|
||||
// free all mapped PDOs
|
||||
list_for_each_entry_safe(pdo, next, &sync->pdos, list) {
|
||||
list_del(&pdo->list);
|
||||
ec_pdo_clear(pdo);
|
||||
kfree(pdo);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* \return Type of PDOs covered by the given sync manager.
|
||||
*/
|
||||
|
||||
ec_pdo_type_t ec_sync_get_pdo_type(
|
||||
const ec_sync_t *sync /**< EtherCAT sync manager */
|
||||
ec_direction_t ec_sync_direction(
|
||||
const ec_sync_t *sync /**< EtherCAT sync manager. */
|
||||
)
|
||||
{
|
||||
int index = sync->index;
|
||||
@@ -215,11 +127,11 @@ ec_pdo_type_t ec_sync_get_pdo_type(
|
||||
}
|
||||
|
||||
if (index < 0 || index > 1) {
|
||||
EC_WARN("ec_sync_get_pdo_type(): invalid sync manager index.\n");
|
||||
return EC_RX_PDO;
|
||||
EC_WARN("ec_sync_get_direction(): invalid sync manager index.\n");
|
||||
return EC_DIR_OUTPUT;
|
||||
}
|
||||
|
||||
return (ec_pdo_type_t) index;
|
||||
return (ec_direction_t) index;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
+24
-39
@@ -31,10 +31,9 @@
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
\file
|
||||
EtherCAT sync manager.
|
||||
*/
|
||||
/** \file
|
||||
* EtherCAT sync manager.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@@ -44,60 +43,46 @@
|
||||
#include <linux/list.h>
|
||||
|
||||
#include "../include/ecrt.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "pdo_mapping.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** size of a sync manager configuration page */
|
||||
#define EC_SYNC_SIZE 8
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* EtherCAT sync manager PDO mapping information source.
|
||||
/** EtherCAT sync manager PDO mapping information source.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
EC_SYNC_MAPPING_NONE, /**< No PDO mapping information */
|
||||
EC_SYNC_MAPPING_SII, /**< PDO mapping information from SII */
|
||||
EC_SYNC_MAPPING_COE /**< PDO mapping information from CoE dictionary */
|
||||
}
|
||||
ec_sync_mapping_source_t;
|
||||
EC_SYNC_MAPPING_NONE, /**< No PDO mapping information. */
|
||||
EC_SYNC_MAPPING_SII, /**< PDO mapping information from SII. */
|
||||
EC_SYNC_MAPPING_COE, /**< PDO mapping information from CoE dictionary. */
|
||||
EC_SYNC_MAPPING_CUSTOM, /**< PDO mapping configured externally. */
|
||||
} ec_sync_mapping_source_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Sync manager.
|
||||
/** Sync manager.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ec_slave_t *slave; /**< slave, the sync manager belongs to */
|
||||
unsigned int index; /**< sync manager index */
|
||||
uint16_t physical_start_address; /**< physical start address */
|
||||
uint16_t length; /**< data length in bytes */
|
||||
uint8_t control_register; /**< control register value */
|
||||
uint8_t enable; /**< enable bit */
|
||||
|
||||
uint16_t est_length; /**< used to calculate the length via PDO ranges */
|
||||
struct list_head pdos; /**< list of mapped PDOs */
|
||||
unsigned int alt_mapping; /**< alternative mapping configured */
|
||||
ec_sync_mapping_source_t mapping_source; /**< pdo mapping source */
|
||||
}
|
||||
ec_sync_t;
|
||||
typedef struct {
|
||||
ec_slave_t *slave; /**< Slave, the sync manager belongs to. */
|
||||
unsigned int index; /**< Sync manager index. */
|
||||
uint16_t physical_start_address; /**< Physical start address. */
|
||||
uint16_t length; /**< Data length in bytes. */
|
||||
uint8_t control_register; /**< Control register value. */
|
||||
uint8_t enable; /**< Enable bit. */
|
||||
ec_pdo_mapping_t mapping; /**< Current Pdo mapping. */
|
||||
ec_sync_mapping_source_t mapping_source; /**< Pdo mapping source. */
|
||||
} ec_sync_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_sync_init(ec_sync_t *, ec_slave_t *, unsigned int);
|
||||
void ec_sync_clear(ec_sync_t *);
|
||||
|
||||
uint16_t ec_sync_size(const ec_sync_t *);
|
||||
void ec_sync_config(const ec_sync_t *, uint8_t *);
|
||||
void ec_sync_config(const ec_sync_t *, uint16_t, uint8_t *);
|
||||
|
||||
int ec_sync_add_pdo(ec_sync_t *, const ec_pdo_t *);
|
||||
void ec_sync_clear_pdos(ec_sync_t *);
|
||||
|
||||
ec_pdo_type_t ec_sync_get_pdo_type(const ec_sync_t *);
|
||||
ec_direction_t ec_sync_direction(const ec_sync_t *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
Reference in New Issue
Block a user