Introduced master status, ecrt_master_get_status(), tainted flag,
authorFlorian Pose <fp@igh-essen.com>
Mon, 05 Mar 2007 10:35:50 +0000
changeset 612 aede068f9a74
parent 611 16498ed938f4
child 613 bf28ede88c70
Introduced master status, ecrt_master_get_status(), tainted flag,
pdos_registered flags and pdo_slaves_offline counter.
NEWS
TODO
examples/mini/mini.c
include/ecrt.h
master/fsm_master.c
master/fsm_master.h
master/master.c
master/master.h
master/slave.c
master/slave.h
--- 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 */