Master accepting two devices. redundancy
authorFlorian Pose <fp@igh-essen.com>
Wed, 09 Nov 2011 12:05:44 +0100
branchredundancy
changeset 2156 71425e6120d8
parent 2142 26c74f035ab0
child 2157 8fa0571f9996
Master accepting two devices.
master/device.c
master/module.c
script/sysconfig/ethercat
tool/CommandMaster.cpp
--- a/master/device.c	Wed Nov 09 09:55:58 2011 +0100
+++ b/master/device.c	Wed Nov 09 12:05:44 2011 +0100
@@ -496,10 +496,21 @@
 void ecdev_withdraw(ec_device_t *device /**< EtherCAT device */)
 {
     ec_master_t *master = device->master;
-    char str[20];
-
-    ec_mac_print(device->dev->dev_addr, str);
-    EC_MASTER_INFO(master, "Releasing main device %s.\n", str);
+    char dev_str[20], mac_str[20];
+
+    ec_mac_print(device->dev->dev_addr, mac_str);
+
+    if (device == &master->main_device) {
+        sprintf(dev_str, "main");
+    } else if (device == &master->backup_device) {
+        sprintf(dev_str, "backup");
+    } else {
+        EC_MASTER_WARN(master, "%s() called with unknown device %s!\n",
+                __func__, mac_str);
+        sprintf(dev_str, "UNKNOWN");
+    }
+
+    EC_MASTER_INFO(master, "Releasing %s device %s.\n", dev_str, mac_str);
     
     down(&master->device_sem);
     ec_device_detach(device);
@@ -516,17 +527,22 @@
 int ecdev_open(ec_device_t *device /**< EtherCAT device */)
 {
     int ret;
+    ec_master_t *master = device->master;
 
     ret = ec_device_open(device);
     if (ret) {
-        EC_MASTER_ERR(device->master, "Failed to open device!\n");
+        EC_MASTER_ERR(master, "Failed to open device!\n");
         return ret;
     }
 
-    ret = ec_master_enter_idle_phase(device->master);
-    if (ret) {
-        EC_MASTER_ERR(device->master, "Failed to enter IDLE phase!\n");
-        return ret;
+    if (master->main_device.open &&
+            (ec_mac_is_zero(master->backup_mac) ||
+             master->backup_device.open)) {
+        ret = ec_master_enter_idle_phase(device->master);
+        if (ret) {
+            EC_MASTER_ERR(device->master, "Failed to enter IDLE phase!\n");
+            return ret;
+        }
     }
 
     return 0;
@@ -541,10 +557,15 @@
  */
 void ecdev_close(ec_device_t *device /**< EtherCAT device */)
 {
-    ec_master_leave_idle_phase(device->master);
-
-    if (ec_device_close(device))
-        EC_MASTER_WARN(device->master, "Failed to close device!\n");
+    ec_master_t *master = device->master;
+
+    if (master->phase == EC_IDLE) {
+        ec_master_leave_idle_phase(master);
+    }
+
+    if (ec_device_close(device)) {
+        EC_MASTER_WARN(master, "Failed to close device!\n");
+    }
 }
 
 /*****************************************************************************/
--- a/master/module.c	Wed Nov 09 09:55:58 2011 +0100
+++ b/master/module.c	Wed Nov 09 12:05:44 2011 +0100
@@ -467,34 +467,43 @@
 
     for (i = 0; i < master_count; i++) {
         master = &masters[i];
+        ec_mac_print(net_dev->dev_addr, str);
 
         down(&master->device_sem);
-        if (master->main_device.dev) { // master already has a device
-            up(&master->device_sem);
-            continue;
-        }
-            
-        if (ec_mac_equal(master->main_mac, net_dev->dev_addr)
-                || ec_mac_is_broadcast(master->main_mac)) {
-            ec_mac_print(net_dev->dev_addr, str);
-            EC_INFO("Accepting device %s for master %u.\n",
+
+        if (!master->main_device.dev
+                && (ec_mac_equal(master->main_mac, net_dev->dev_addr)
+                    || ec_mac_is_broadcast(master->main_mac))) {
+
+            EC_INFO("Accepting %s as main device for master %u.\n",
                     str, master->index);
 
             ec_device_attach(&master->main_device, net_dev, poll, module);
             up(&master->device_sem);
-            
+
             snprintf(net_dev->name, IFNAMSIZ, "ec%u", master->index);
 
             return &master->main_device; // offer accepted
-        }
-        else {
+
+        } else if (!master->backup_device.dev
+                && ec_mac_equal(master->backup_mac, net_dev->dev_addr)) {
+
+            EC_INFO("Accepting %s as backup device for master %u.\n",
+                    str, master->index);
+
+            ec_device_attach(&master->backup_device, net_dev, poll,
+                    module);
             up(&master->device_sem);
 
-            if (master->debug_level) {
-                ec_mac_print(net_dev->dev_addr, str);
-                EC_MASTER_DBG(master, 0, "Master declined device %s.\n",
-                        str);
-            }
+            snprintf(net_dev->name, IFNAMSIZ, "ecb%u", master->index);
+
+            return &master->backup_device; // offer accepted
+
+        } else {
+
+            up(&master->device_sem);
+
+            EC_MASTER_DBG(master, 1, "Master declined device %s.\n", str);
         }
     }
 
--- a/script/sysconfig/ethercat	Wed Nov 09 09:55:58 2011 +0100
+++ b/script/sysconfig/ethercat	Wed Nov 09 12:05:44 2011 +0100
@@ -4,10 +4,12 @@
 #
 #  $Id$
 #
+#  vim: spelllang=en spell tw=78
+#
 #------------------------------------------------------------------------------
 
 #
-# Master devices.
+# Main Ethernet devices.
 #
 # The MASTER<X>_DEVICE variable specifies the Ethernet device for a master
 # with index 'X'.
@@ -26,6 +28,15 @@
 #MASTER1_DEVICE=""
 
 #
+# Backup Ethernet devices
+#
+# The MASTER<X>_BACKUP variables specify the devices used for redundancy. They
+# behaves nearly the same as the MASTER<X>_DEVICE variable, except that it
+# does not interpret the ff:ff:ff:ff:ff:ff address.
+#
+#MASTER0_BACKUP=""
+
+#
 # Ethernet driver modules to use for EtherCAT operation.
 #
 # Specify a non-empty list of Ethernet drivers, that shall be used for EtherCAT
--- a/tool/CommandMaster.cpp	Wed Nov 09 09:55:58 2011 +0100
+++ b/tool/CommandMaster.cpp	Wed Nov 09 12:05:44 2011 +0100
@@ -93,7 +93,7 @@
             << "  Phase: ";
 
         switch (data.phase) {
-            case 0:  cout << "Waiting for device..."; break;
+            case 0:  cout << "Waiting for device(s)..."; break;
             case 1:  cout << "Idle"; break;
             case 2:  cout << "Operation"; break;
             default: cout << "???";