Slave alias implementiert.
authorFlorian Pose <fp@igh-essen.com>
Mon, 20 Mar 2006 15:28:25 +0000
changeset 114 e4b4b5a85e75
parent 113 a3dbd6bc8fce
child 115 509afb04ded0
Slave alias implementiert.
include/ecrt.h
master/master.c
master/slave.c
master/slave.h
mini/mini.c
--- a/include/ecrt.h	Mon Mar 20 13:36:10 2006 +0000
+++ b/include/ecrt.h	Mon Mar 20 15:28:25 2006 +0000
@@ -69,6 +69,8 @@
                          uint16_t sdo_index,
                          uint8_t sdo_subindex,
                          uint32_t *value);
+int ecrt_master_write_slave_alias(ec_master_t *master,
+                                  const char *slave_address, uint16_t alias);
 
 /*****************************************************************************/
 // Domain Methods
--- a/master/master.c	Mon Mar 20 13:36:10 2006 +0000
+++ b/master/master.c	Mon Mar 20 15:28:25 2006 +0000
@@ -524,11 +524,13 @@
    Wandelt eine ASCII-kodierte Bus-Adresse in einen Slave-Zeiger.
 
    Gültige Adress-Strings sind Folgende:
-
    - \a "X" = der X. Slave im Bus,
    - \a "X:Y" = der Y. Slave hinter dem X. Buskoppler,
-   - \a "#X" = der Slave mit der SSID X,
-   - \a "#X:Y" = der Y. Slave hinter dem Buskoppler mit der SSID X.
+   - \a "#X" = der Slave mit dem Alias X,
+   - \a "#X:Y" = der Y. Slave hinter dem Buskoppler mit dem Alias X.
+
+   X und Y fangen immer bei 0 an und können auch hexadezimal oder oktal
+   angegeben werden (mit entsprechendem Prefix).
 
    \return Zeiger auf Slave bei Erfolg, sonst NULL
 */
@@ -541,65 +543,94 @@
 {
     unsigned long first, second;
     char *remainder, *remainder2;
-    unsigned int i;
+    unsigned int i, alias_requested, alias_slave_index, alias_found;
     int coupler_idx, slave_idx;
     ec_slave_t *slave;
 
     if (!address || address[0] == 0) return NULL;
 
+    alias_requested = 0;
+    alias_slave_index = 0;
     if (address[0] == '#') {
-        EC_ERR("Bus ID \"%s\" - #<SSID> not implemented yet!\n", address);
-        return NULL;
+        alias_requested = 1;
+        address++;
     }
 
     first = simple_strtoul(address, &remainder, 0);
     if (remainder == address) {
-        EC_ERR("Bus ID \"%s\" - First number empty!\n", address);
+        EC_ERR("Slave address \"%s\" - First number empty!\n", address);
         return NULL;
     }
 
+    if (alias_requested) {
+        alias_found = 0;
+        for (i = 0; i < master->slave_count; i++) {
+            if (master->slaves[i].sii_alias == first) {
+                alias_slave_index = i;
+                alias_found = 1;
+                break;
+            }
+        }
+        if (!alias_found) {
+            EC_ERR("Slave address \"%s\" - Alias not found!\n", address);
+            return NULL;
+        }
+    }
+
     if (!remainder[0]) { // absolute position
-        if (first < master->slave_count) {
-            return master->slaves + first;
-        }
-
-        EC_ERR("Bus ID \"%s\" - Absolute position invalid!\n", address);
-    }
-
+        if (alias_requested) {
+            return master->slaves + alias_slave_index;
+        }
+        else {
+            if (first < master->slave_count) {
+                return master->slaves + first;
+            }
+            EC_ERR("Slave address \"%s\" - Absolute position invalid!\n",
+                   address);
+        }
+    }
     else if (remainder[0] == ':') { // field position
-
         remainder++;
         second = simple_strtoul(remainder, &remainder2, 0);
 
         if (remainder2 == remainder) {
-            EC_ERR("Bus ID \"%s\" - Sencond number empty!\n", address);
+            EC_ERR("Slave address \"%s\" - Second number empty!\n", address);
             return NULL;
         }
 
         if (remainder2[0]) {
-            EC_ERR("Bus ID \"%s\" - Invalid trailer (2)!\n", address);
+            EC_ERR("Slave address \"%s\" - Invalid trailer!\n", address);
             return NULL;
         }
 
-        coupler_idx = -1;
-        slave_idx = 0;
-        for (i = 0; i < master->slave_count; i++, slave_idx++) {
-            slave = master->slaves + i;
-            if (!slave->type) continue;
-
-            if (slave->type->bus_coupler) {
-                coupler_idx++;
-                slave_idx = 0;
+        if (alias_requested) {
+            for (i = alias_slave_index + 1; i < master->slave_count; i++) {
+                slave = master->slaves + i;
+                if (!slave->type || slave->type->bus_coupler) break;
+                if (i - alias_slave_index - 1 == second) return slave;
             }
-
-            if (coupler_idx == first && slave_idx == second) return slave;
-        }
-    }
-
+            EC_ERR("Slave address \"%s\" - Bus coupler %i has no %lu. slave"
+                   " following!\n", address,
+                   (master->slaves + alias_slave_index)->ring_position,
+                   second);
+            return NULL;
+        }
+        else {
+            coupler_idx = -1;
+            slave_idx = 0;
+            for (i = 0; i < master->slave_count; i++, slave_idx++) {
+                slave = master->slaves + i;
+                if (!slave->type) continue; // FIXME
+                if (slave->type->bus_coupler) {
+                    coupler_idx++;
+                    slave_idx = 0;
+                }
+                if (coupler_idx == first && slave_idx == second) return slave;
+            }
+        }
+    }
     else
-        EC_ERR("Bus ID \"%s\" - Invalid trailer!\n", address);
-
-    // FIXME ???
+        EC_ERR("Slave address \"%s\" - Invalid format!\n", address);
 
     return NULL;
 }
@@ -1030,6 +1061,29 @@
 
 /*****************************************************************************/
 
+/**
+   Schreibt den "Configured station alias".
+
+   \return 0, wenn alles ok, sonst < 0
+*/
+
+int ecrt_master_write_slave_alias(ec_master_t *master,
+                                  /** EtherCAT-Master */
+                                  const char *slave_address,
+                                  /** Slave-Adresse,
+                                      siehe ec_master_slave_address() */
+                                  uint16_t alias
+                                  /** Neuer Alias */
+                                  )
+{
+    ec_slave_t *slave;
+    if (!(slave = ec_master_slave_address(master, slave_address)))
+        return -1;
+    return ec_slave_sii_write(slave, 0x0004, alias);
+}
+
+/*****************************************************************************/
+
 EXPORT_SYMBOL(ecrt_master_create_domain);
 EXPORT_SYMBOL(ecrt_master_activate);
 EXPORT_SYMBOL(ecrt_master_deactivate);
@@ -1039,6 +1093,7 @@
 EXPORT_SYMBOL(ecrt_master_async_receive);
 EXPORT_SYMBOL(ecrt_master_debug);
 EXPORT_SYMBOL(ecrt_master_print);
+EXPORT_SYMBOL(ecrt_master_write_slave_alias);
 
 /*****************************************************************************/
 
--- a/master/slave.c	Mon Mar 20 13:36:10 2006 +0000
+++ b/master/slave.c	Mon Mar 20 15:28:25 2006 +0000
@@ -34,6 +34,7 @@
     slave->base_sync_count = 0;
     slave->ring_position = 0;
     slave->station_address = 0;
+    slave->sii_alias = 0;
     slave->sii_vendor_id = 0;
     slave->sii_product_code = 0;
     slave->sii_revision_number = 0;
@@ -85,6 +86,12 @@
 
     // Read identification from "Slave Information Interface" (SII)
 
+    if (unlikely(ec_slave_sii_read(slave, 0x0004,
+                                   (uint32_t *) &slave->sii_alias))) {
+        EC_ERR("Could not read SII alias!\n");
+        return -1;
+    }
+
     if (unlikely(ec_slave_sii_read(slave, 0x0008, &slave->sii_vendor_id))) {
         EC_ERR("Could not read SII vendor id!\n");
         return -1;
@@ -134,10 +141,9 @@
 
     // Initiate read operation
 
-    EC_WRITE_U8 (data,     0x00);
-    EC_WRITE_U8 (data + 1, 0x01);
-    EC_WRITE_U16(data + 2, offset);
-    EC_WRITE_U16(data + 4, 0x0000);
+    EC_WRITE_U8 (data,     0x00); // read-only access
+    EC_WRITE_U8 (data + 1, 0x01); // request read operation
+    EC_WRITE_U32(data + 2, offset);
 
     ec_command_init_npwr(&command, slave->station_address, 0x502, 6, data);
     if (unlikely(ec_master_simple_io(slave->master, &command))) {
@@ -166,7 +172,7 @@
         end = get_cycles();
 
         if (likely((EC_READ_U8(command.data + 1) & 0x81) == 0)) {
-            memcpy(target, command.data + 6, 4);
+            *target = EC_READ_U32(command.data + 6);
             return 0;
         }
 
@@ -180,6 +186,81 @@
 /*****************************************************************************/
 
 /**
+   Schreibt Daten in das Slave-Information-Interface
+   eines EtherCAT-Slaves.
+
+   \return 0 bei Erfolg, sonst < 0
+*/
+
+int ec_slave_sii_write(ec_slave_t *slave,
+                       /**< EtherCAT-Slave */
+                       uint16_t offset,
+                       /**< Adresse des zu lesenden SII-Registers */
+                       uint16_t value
+                       /**< Zu schreibender Wert */
+                       )
+{
+    ec_command_t command;
+    uint8_t data[8];
+    cycles_t start, end, timeout;
+
+    EC_INFO("SII-write (slave %i, offset 0x%04X, value 0x%04X)\n",
+            slave->ring_position, offset, value);
+
+    // Initiate write operation
+
+    EC_WRITE_U8 (data,     0x01); // enable write access
+    EC_WRITE_U8 (data + 1, 0x02); // request write operation
+    EC_WRITE_U32(data + 2, offset);
+    EC_WRITE_U16(data + 6, value);
+
+    ec_command_init_npwr(&command, slave->station_address, 0x502, 8, data);
+    if (unlikely(ec_master_simple_io(slave->master, &command))) {
+        EC_ERR("SII-write failed on slave %i!\n", slave->ring_position);
+        return -1;
+    }
+
+    // Der Slave legt die Informationen des Slave-Information-Interface
+    // in das Datenregister und löscht daraufhin ein Busy-Bit. Solange
+    // den Status auslesen, bis das Bit weg ist.
+
+    start = get_cycles();
+    timeout = cpu_khz; // 1ms
+
+    while (1)
+    {
+        udelay(10);
+
+        ec_command_init_nprd(&command, slave->station_address, 0x502, 2);
+        if (unlikely(ec_master_simple_io(slave->master, &command))) {
+            EC_ERR("Getting SII-write status failed on slave %i!\n",
+                   slave->ring_position);
+            return -1;
+        }
+
+        end = get_cycles();
+
+        if (likely((EC_READ_U8(command.data + 1) & 0x82) == 0)) {
+            if (EC_READ_U8(command.data + 1) & 0x40) {
+                EC_ERR("SII-write failed!\n");
+                return -1;
+            }
+            else {
+                EC_INFO("SII-write succeeded!\n");
+                return 0;
+            }
+        }
+
+        if (unlikely((end - start) >= timeout)) {
+            EC_ERR("SSI-write: Slave %i timed out!\n", slave->ring_position);
+            return -1;
+        }
+    }
+}
+
+/*****************************************************************************/
+
+/**
    Bestätigt einen Fehler beim Zustandswechsel.
 
    \todo Funktioniert noch nicht...
@@ -377,6 +458,8 @@
             slave->base_fmmu_count, slave->base_sync_count);
 
     EC_INFO("  Slave information interface:\n");
+    EC_INFO("    Configured station alias: 0x%04X (%i)\n", slave->sii_alias,
+            slave->sii_alias);
     EC_INFO("    Vendor-ID: 0x%08X, Product code: 0x%08X\n",
             slave->sii_vendor_id, slave->sii_product_code);
     EC_INFO("    Revision number: 0x%08X, Serial number: 0x%08X\n",
@@ -429,3 +512,4 @@
 ;;; c-basic-offset:4 ***
 ;;; End: ***
 */
+
--- a/master/slave.h	Mon Mar 20 13:36:10 2006 +0000
+++ b/master/slave.h	Mon Mar 20 15:28:25 2006 +0000
@@ -71,6 +71,7 @@
     uint16_t base_sync_count; /**< Anzahl unterstützter Sync-Manager */
 
     // Slave information interface
+    uint16_t sii_alias; /**< Configured station alias */
     uint32_t sii_vendor_id; /**< Identifikationsnummer des Herstellers */
     uint32_t sii_product_code; /**< Herstellerspezifischer Produktcode */
     uint32_t sii_revision_number; /**< Revisionsnummer */
@@ -94,6 +95,7 @@
 // Slave control
 int ec_slave_fetch(ec_slave_t *);
 int ec_slave_sii_read(ec_slave_t *, uint16_t, uint32_t *);
+int ec_slave_sii_write(ec_slave_t *, uint16_t, uint16_t);
 int ec_slave_state_change(ec_slave_t *, uint8_t);
 int ec_slave_set_fmmu(ec_slave_t *, const ec_domain_t *, const ec_sync_t *);
 
--- a/mini/mini.c	Mon Mar 20 13:36:10 2006 +0000
+++ b/mini/mini.c	Mon Mar 20 15:28:25 2006 +0000
@@ -45,7 +45,7 @@
     {NULL,          "6", "Beckhoff", "EL1014", "InputValue",  0},
     {NULL,          "7", "Beckhoff", "EL2004", "OutputValue", 0},
     {NULL,          "8", "Beckhoff", "EL4132", "OutputValue", 0},
-    {NULL,          "9", "Beckhoff", "EL4132", "OutputValue", 0},
+    {NULL,   "#48879:8", "Beckhoff", "EL4132", "OutputValue", 0},
     {}
 };
 
@@ -144,6 +144,14 @@
 
     //ecrt_master_debug(master, 0);
 
+#if 0
+    printk(KERN_INFO "Writing alias...\n");
+    if (ecrt_master_write_slave_alias(master, "0", 0xBEEF)) {
+        printk(KERN_ERR "EtherCAT: Failed to write alias!\n");
+        goto out_deactivate;
+    }
+#endif
+
 #ifdef ASYNC
     // Einmal senden und warten...
     ecrt_master_prepare_async_io(master);