Introduced master status, ecrt_master_get_status(), tainted flag,
pdos_registered flags and pdo_slaves_offline counter.
This commit is contained in:
parent
43075a1589
commit
b4bfda2e62
4
NEWS
4
NEWS
|
|
@ -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
11
TODO
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
Loading…
Reference in New Issue