--- a/NEWS Mon Mar 05 10:00:18 2007 +0000
+++ b/NEWS Mon Mar 05 10:35:50 2007 +0000
@@ -15,12 +15,14 @@
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.
--- a/TODO Mon Mar 05 10:00:18 2007 +0000
+++ b/TODO Mon Mar 05 10:35:50 2007 +0000
@@ -10,15 +10,14 @@
- 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 @@
- 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.
--- a/examples/mini/mini.c Mon Mar 05 10:00:18 2007 +0000
+++ b/examples/mini/mini.c Mon Mar 05 10:35:50 2007 +0000
@@ -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;
-#endif
-
-void *r_dig_out;
+static void *r_inputs;
+static void *r_outputs;
+#endif
+
+static void *r_dig_out;
#if 1
ec_pdo_reg_t domain1_pdos[] = {
@@ -90,6 +93,26 @@
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 @@
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");
- goto out_release_master;
- }
-
- printk(KERN_INFO "Registering PDOs...\n");
+ printk(KERN_ERR PFX "Domain creation failed!\n");
+ goto out_release_master;
+ }
+
+ 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 @@
#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 @@
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");
- goto out_release_master;
- }
-
- printk("Starting cyclic sample thread.\n");
+ printk(KERN_ERR PFX "Failed to activate master!\n");
+ goto out_release_master;
+ }
+
+ 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 @@
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");
}
/*****************************************************************************/
--- a/include/ecrt.h Mon Mar 05 10:00:18 2007 +0000
+++ b/include/ecrt.h Mon Mar 05 10:35:50 2007 +0000
@@ -77,8 +77,31 @@
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 @@
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 @@
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
--- a/master/fsm_master.c Mon Mar 05 10:00:18 2007 +0000
+++ b/master/fsm_master.c Mon Mar 05 10:35:50 2007 +0000
@@ -78,6 +78,7 @@
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 @@
}
else {
EC_WARN("Invalid slave count. Bus in tainted state.\n");
+ fsm->tainted = 1;
}
}
}
@@ -640,6 +642,7 @@
// 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);
--- a/master/fsm_master.h Mon Mar 05 10:00:18 2007 +0000
+++ b/master/fsm_master.h Mon Mar 05 10:35:50 2007 +0000
@@ -100,6 +100,8 @@
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 */
--- a/master/master.c Mon Mar 05 10:00:18 2007 +0000
+++ b/master/master.c Mon Mar 05 10:35:50 2007 +0000
@@ -477,6 +477,7 @@
}
master->eoe_checked = 0; // allow starting EoE again
+ master->pdo_slaves_offline = 0; // assume all PDO slaves online
return 0;
@@ -1655,6 +1656,22 @@
/*****************************************************************************/
+/**
+ * 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_run);
EXPORT_SYMBOL(ecrt_master_callbacks);
EXPORT_SYMBOL(ecrt_master_get_slave);
+EXPORT_SYMBOL(ecrt_master_get_status);
/** \endcond */
--- a/master/master.h Mon Mar 05 10:00:18 2007 +0000
+++ b/master/master.h Mon Mar 05 10:35:50 2007 +0000
@@ -120,6 +120,9 @@
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 */
--- a/master/slave.c Mon Mar 05 10:00:18 2007 +0000
+++ b/master/slave.c Mon Mar 05 10:35:50 2007 +0000
@@ -118,6 +118,7 @@
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 @@
// 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 @@
{
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 @@
fmmu->logical_start_address = 0;
slave->fmmu_count++;
+ slave->pdos_registered = 1;
ec_slave_request_state(slave, EC_SLAVE_STATE_OP);
--- a/master/slave.h Mon Mar 05 10:00:18 2007 +0000
+++ b/master/slave.h Mon Mar 05 10:35:50 2007 +0000
@@ -206,6 +206,7 @@
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 */