Introduced master status, ecrt_master_get_status(), tainted flag,

pdos_registered flags and pdo_slaves_offline counter.
This commit is contained in:
Florian Pose 2007-03-05 10:35:50 +00:00
parent 43075a1589
commit b4bfda2e62
10 changed files with 112 additions and 33 deletions

4
NEWS
View File

@ -15,12 +15,14 @@ Changes in version 1.3.0:
device ID lists.
* Changed format of sysconfig file and accordingly adjusted functionality
of the init script to handle device ID lists.
* Realtime interface changes:
- Added ecrt_master_get_status() to get information about the bus.
* Device interface changes:
- Replaced ecdev_register() and ecdev_unregister() with ecdev_offer() and
ecdev_withdraw(), respectively. The device modules now offer all their
devices to the master, which decides, which ones to register.
* All EEPROM write operations from user space are now blocking until
completion and returning appropriate error codes.
writing has finished and return appropriate error codes.
* Implemented setting of secondary slave address (alias) via sysfs.
* Removed annoying eeprom_write_enable file. EEPROM writing always enabled.
* Removed EtherCAT line comments from 8139too drivers.

11
TODO
View File

@ -10,15 +10,14 @@ $Id$
- Remove ecrt_master_run(). Make master FSM run in process context instead.
- Remove addressing scheme "X:Y".
- Allow only MAC address as device ID.
- Interface/buffers for asynchronous domain IO.
- Remove ugly ec_slave_is_coupler() and ec_slave_has_subbus().
- Add statistics object.
* Future features:
- SDO dictionary and -access in operation mode.
- SDO write access in sysfs.
- Speed up IDLE-FSM through fast mode with schedule().
- Evaluate EEPROM contents after writing.
* Future features:
- Interface/buffers for asynchronous domain IO.
- Distributed clocks.
- Read dynamic PDO mapping from SDO dictionary (see can-cia.org: cia301ds4).
- Redundancy with 2 network adapters.
@ -27,13 +26,13 @@ $Id$
- Optimize alignment of process data.
- Calculate expected working counter for domains.
* Smaller changes:
* Smaller issues:
- Simplify FSMs with <state>_enter() functions.
- Dynamic creation of EoE handlers.
- Output intermediate results during lsec.
- State change FSM: Follow spontaneous state changes.
* Less important changes:
* Less important issues:
- Implement all EtherCAT datagram types.
- File access over EtherCAT (FoE).
- Allow VLAN tagging.

View File

@ -39,26 +39,29 @@
#include "../../include/ecrt.h" // EtherCAT realtime interface
#include "../../include/ecdb.h" // EtherCAT slave database
#define PFX "ec_mini: "
#define FREQUENCY 100
//#define KBUS
/*****************************************************************************/
struct timer_list timer;
static struct timer_list timer;
// EtherCAT
ec_master_t *master = NULL;
ec_domain_t *domain1 = NULL;
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 = {};
// data fields
#ifdef KBUS
void *r_inputs;
void *r_outputs;
static void *r_inputs;
static void *r_outputs;
#endif
void *r_dig_out;
static void *r_dig_out;
#if 1
ec_pdo_reg_t domain1_pdos[] = {
@ -90,6 +93,26 @@ void run(unsigned long data)
else {
counter = FREQUENCY;
blink = !blink;
spin_lock(&master_lock);
ecrt_master_get_status(master, &master_status);
spin_unlock(&master_lock);
if (master_status.bus_status != old_status.bus_status) {
printk(KERN_INFO PFX "bus status changed to %u.\n",
master_status.bus_status);
}
if (master_status.bus_tainted != old_status.bus_tainted) {
printk(KERN_INFO PFX "tainted flag changed to %u.\n",
master_status.bus_tainted);
}
if (master_status.slaves_responding !=
old_status.slaves_responding) {
printk(KERN_INFO PFX "slaves_responding changed to %u.\n",
master_status.slaves_responding);
}
old_status = master_status;
}
#ifdef KBUS
@ -135,25 +158,25 @@ int __init init_mini_module(void)
ec_slave_t *slave;
#endif
printk(KERN_INFO "=== Starting Minimal EtherCAT environment... ===\n");
printk(KERN_INFO PFX "Starting...\n");
if (!(master = ecrt_request_master(0))) {
printk(KERN_ERR "Requesting master 0 failed!\n");
printk(KERN_ERR PFX "Requesting master 0 failed!\n");
goto out_return;
}
ecrt_master_callbacks(master, request_lock, release_lock, NULL);
printk(KERN_INFO "Registering domain...\n");
printk(KERN_INFO PFX "Registering domain...\n");
if (!(domain1 = ecrt_master_create_domain(master))) {
printk(KERN_ERR "Domain creation failed!\n");
printk(KERN_ERR PFX "Domain creation failed!\n");
goto out_release_master;
}
printk(KERN_INFO "Registering PDOs...\n");
printk(KERN_INFO PFX "Registering PDOs...\n");
#if 1
if (ecrt_domain_register_pdo_list(domain1, domain1_pdos)) {
printk(KERN_ERR "PDO registration failed!\n");
printk(KERN_ERR PFX "PDO registration failed!\n");
goto out_release_master;
}
#endif
@ -161,12 +184,12 @@ int __init init_mini_module(void)
#ifdef KBUS
if (!ecrt_domain_register_pdo_range(domain1, "0", Beckhoff_BK1120,
EC_DIR_OUTPUT, 0, 4, &r_outputs)) {
printk(KERN_ERR "PDO registration failed!\n");
printk(KERN_ERR PFX "PDO registration failed!\n");
goto out_release_master;
}
if (!ecrt_domain_register_pdo_range(domain1, "0", Beckhoff_BK1120,
EC_DIR_INPUT, 0, 4, &r_inputs)) {
printk(KERN_ERR "PDO registration failed!\n");
printk(KERN_ERR PFX "PDO registration failed!\n");
goto out_release_master;
}
#endif
@ -179,19 +202,19 @@ int __init init_mini_module(void)
goto out_release_master;
#endif
printk(KERN_INFO "Activating master...\n");
printk(KERN_INFO PFX "Activating master...\n");
if (ecrt_master_activate(master)) {
printk(KERN_ERR "Failed to activate master!\n");
printk(KERN_ERR PFX "Failed to activate master!\n");
goto out_release_master;
}
printk("Starting cyclic sample thread.\n");
printk(KERN_INFO PFX "Starting cyclic sample thread.\n");
init_timer(&timer);
timer.function = run;
timer.expires = jiffies + 10;
add_timer(&timer);
printk(KERN_INFO "=== Minimal EtherCAT environment started. ===\n");
printk(KERN_INFO PFX "Started.\n");
return 0;
out_release_master:
@ -204,13 +227,13 @@ int __init init_mini_module(void)
void __exit cleanup_mini_module(void)
{
printk(KERN_INFO "=== Stopping Minimal EtherCAT environment... ===\n");
printk(KERN_INFO PFX "Stopping...\n");
del_timer_sync(&timer);
printk(KERN_INFO "Releasing master...\n");
printk(KERN_INFO PFX "Releasing master...\n");
ecrt_release_master(master);
printk(KERN_INFO "=== Minimal EtherCAT environment stopped. ===\n");
printk(KERN_INFO PFX "Stopped.\n");
}
/*****************************************************************************/

View File

@ -76,9 +76,32 @@ typedef struct ec_domain ec_domain_t; /**< \see ec_domain */
struct ec_slave;
typedef struct ec_slave ec_slave_t; /**< \see ec_slave */
/**
* Bus status.
*/
typedef enum {
EC_BUS_FAILURE, // some slaves offline
EC_BUS_OK, // all slaves online
EC_BUS_REDUNDANCY // bus interrupted, but redundancy active
}
ec_bus_status_t;
/**
* Master status.
* This is used for the output parameter of ecrt_master_get_status().
*/
typedef struct {
ec_bus_status_t bus_status;
unsigned int bus_tainted;
unsigned int slaves_responding;
}
ec_master_status_t;
/**
Initialization type for PDO registrations.
This type is used as a parameter for the ec_domain_register_pdo_list()
This type is used as a parameter for the ecrt_domain_register_pdo_list()
function.
*/
@ -95,7 +118,7 @@ typedef struct
ec_pdo_reg_t;
/**
Direction type for ec_domain_register_pdo_range()
Direction type for ecrt_domain_register_pdo_range()
*/
typedef enum {EC_DIR_INPUT, EC_DIR_OUTPUT} ec_direction_t;
@ -127,9 +150,7 @@ void ecrt_master_run(ec_master_t *master);
ec_slave_t *ecrt_master_get_slave(const ec_master_t *, const char *);
/** \cond */
int ecrt_master_state(const ec_master_t *master);
/** \endcond */
void ecrt_master_get_status(const ec_master_t *master, ec_master_status_t *);
/******************************************************************************
* Domain Methods

View File

@ -78,6 +78,7 @@ void ec_fsm_master_init(ec_fsm_master_t *fsm, /**< master state machine */
fsm->topology_change_pending = 0;
fsm->slave_states = EC_SLAVE_STATE_UNKNOWN;
fsm->validate = 0;
fsm->tainted = 0;
// init sub-state-machines
ec_fsm_slave_init(&fsm->fsm_slave, fsm->datagram);
@ -206,6 +207,7 @@ void ec_fsm_master_state_broadcast(ec_fsm_master_t *fsm /**< master state machin
}
else {
EC_WARN("Invalid slave count. Bus in tainted state.\n");
fsm->tainted = 1;
}
}
}
@ -640,6 +642,7 @@ void ec_fsm_master_state_validate_product(ec_fsm_master_t *fsm /**< master state
// have all states been validated?
if (slave->list.next == &fsm->master->slaves) {
fsm->tainted = 0;
fsm->slave = list_entry(fsm->master->slaves.next, ec_slave_t, list);
// start writing addresses to offline slaves
ec_fsm_master_action_addresses(fsm);

View File

@ -100,6 +100,8 @@ struct ec_fsm_master
unsigned int topology_change_pending; /**< bus topology changed */
ec_slave_state_t slave_states; /**< states of responding slaves */
unsigned int validate; /**< non-zero, if validation to do */
unsigned int tainted; /**< non-zero, if the current bus topology does
not meet the initial conditions */
ec_slave_t *slave; /**< current slave */
ec_eeprom_write_request_t *eeprom_request; /**< EEPROM write request */
off_t eeprom_index; /**< index to EEPROM write request data */

View File

@ -477,6 +477,7 @@ int ec_master_enter_operation_mode(ec_master_t *master /**< EtherCAT master */)
}
master->eoe_checked = 0; // allow starting EoE again
master->pdo_slaves_offline = 0; // assume all PDO slaves online
return 0;
@ -1655,6 +1656,22 @@ 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 */
)
{
status->bus_status =
master->pdo_slaves_offline ? EC_BUS_FAILURE : EC_BUS_OK;
status->bus_tainted = master->fsm.tainted;
status->slaves_responding = master->fsm.slaves_responding;
}
/*****************************************************************************/
/** \cond */
EXPORT_SYMBOL(ecrt_master_create_domain);
@ -1664,6 +1681,7 @@ EXPORT_SYMBOL(ecrt_master_receive);
EXPORT_SYMBOL(ecrt_master_run);
EXPORT_SYMBOL(ecrt_master_callbacks);
EXPORT_SYMBOL(ecrt_master_get_slave);
EXPORT_SYMBOL(ecrt_master_get_status);
/** \endcond */

View File

@ -120,6 +120,9 @@ struct ec_master
int debug_level; /**< master debug level */
ec_stats_t stats; /**< cyclic statistics */
unsigned int pdo_slaves_offline; /** number of slaves, for which PDOs
were registered and that are offline
(used for bus status) */
int thread_id; /**< master thread PID */
struct completion thread_exit; /**< thread completion object */

View File

@ -118,6 +118,7 @@ int ec_slave_init(ec_slave_t *slave, /**< EtherCAT slave */
slave->error_flag = 0;
slave->online_state = EC_SLAVE_ONLINE;
slave->fmmu_count = 0;
slave->pdos_registered = 0;
slave->coupler_index = 0;
slave->coupler_subindex = 0xFFFF;
@ -312,6 +313,7 @@ void ec_slave_reset(ec_slave_t *slave /**< EtherCAT slave */)
// remove FMMU configurations
slave->fmmu_count = 0;
slave->pdos_registered = 0;
// free all SDO configurations
list_for_each_entry_safe(sdodata, next_sdodata, &slave->sdo_confs, list) {
@ -361,12 +363,16 @@ void ec_slave_set_online_state(ec_slave_t *slave, /**< EtherCAT slave */
{
if (new_state == EC_SLAVE_OFFLINE &&
slave->online_state == EC_SLAVE_ONLINE) {
if (slave->pdos_registered)
slave->master->pdo_slaves_offline++;
if (slave->master->debug_level)
EC_DBG("Slave %i: offline.\n", slave->ring_position);
}
else if (new_state == EC_SLAVE_ONLINE &&
slave->online_state == EC_SLAVE_OFFLINE) {
slave->error_flag = 0; // clear error flag
if (slave->pdos_registered)
slave->master->pdo_slaves_offline--;
if (slave->master->debug_level) {
char cur_state[EC_STATE_STRING_SIZE];
ec_state_string(slave->current_state, cur_state);
@ -649,6 +655,7 @@ int ec_slave_prepare_fmmu(ec_slave_t *slave, /**< EtherCAT slave */
fmmu->logical_start_address = 0;
slave->fmmu_count++;
slave->pdos_registered = 1;
ec_slave_request_state(slave, EC_SLAVE_STATE_OP);

View File

@ -206,6 +206,7 @@ struct ec_slave
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 */