Variable-sized data fields, BK1120.
authorFlorian Pose <fp@igh-essen.com>
Tue, 20 Jun 2006 14:40:04 +0000
changeset 275 ba51285d4ef6
parent 274 b397aee6e602
child 276 9c4ae9cb5d8d
Variable-sized data fields, BK1120.
examples/mini/mini.c
include/ecrt.h
master/domain.c
master/fsm.c
master/master.c
master/master.h
master/slave.c
master/slave.h
master/types.c
--- a/examples/mini/mini.c	Wed Jun 14 10:23:02 2006 +0000
+++ b/examples/mini/mini.c	Tue Jun 20 14:40:04 2006 +0000
@@ -57,14 +57,14 @@
 
 // data fields
 //void *r_ssi_input, *r_ssi_status, *r_4102[3];
+void *r_kbus_in;
 
 // channels
 uint32_t k_pos;
 uint8_t k_stat;
 
 ec_field_init_t domain1_fields[] = {
-    {NULL, "3", "Beckhoff", "EL5001", "InputValue",   0},
-    {NULL, "2", "Beckhoff", "EL4132", "OutputValue",  0},
+    {&r_kbus_in, "0", "Beckhoff", "BK1120", "Inputs", 0},
     {}
 };
 
@@ -133,6 +133,8 @@
 
 int __init init_mini_module(void)
 {
+    ec_slave_t *slave;
+
     printk(KERN_INFO "=== Starting Minimal EtherCAT environment... ===\n");
 
     if ((master = ecrt_request_master(0)) == NULL) {
@@ -155,6 +157,15 @@
         goto out_release_master;
     }
 
+#if 1
+    printk(KERN_INFO "Setting variable data field sizes...\n");
+    if (!(slave = ecrt_master_get_slave(master, "0"))) {
+        printk(KERN_ERR "Failed to get slave!\n");
+        goto out_deactivate;
+    }
+    ecrt_slave_field_size(slave, "Inputs", 0, 1);
+#endif
+
     printk(KERN_INFO "Activating master...\n");
     if (ecrt_master_activate(master)) {
         printk(KERN_ERR "Failed to activate master!\n");
@@ -191,14 +202,6 @@
     }
 #endif
 
-#if 0
-    printk(KERN_INFO "Writing alias...\n");
-    if (ecrt_slave_sdo_write_exp16(slave, 0xBEEF)) {
-        printk(KERN_ERR "Failed to write alias!\n");
-        goto out_deactivate;
-    }
-#endif
-
 #ifdef ASYNC
     // send once and wait...
     ecrt_master_prepare_async_io(master);
--- a/include/ecrt.h	Wed Jun 14 10:23:02 2006 +0000
+++ b/include/ecrt.h	Tue Jun 20 14:40:04 2006 +0000
@@ -160,7 +160,10 @@
 int ecrt_slave_sdo_read(ec_slave_t *slave, uint16_t sdo_index,
                         uint8_t sdo_subindex, uint8_t *data, size_t *size);
 
-int ecrt_slave_write_alias(ec_slave_t *slave, uint16_t alias);
+int ecrt_slave_write_alias(ec_slave_t *slave, uint16_t alias); // deprecated!
+
+int ecrt_slave_field_size(ec_slave_t *slave, const char *field_name,
+                          unsigned int field_index, size_t size);
 
 /******************************************************************************
  *  Bitwise read/write macros
--- a/master/domain.c	Wed Jun 14 10:23:02 2006 +0000
+++ b/master/domain.c	Tue Jun 20 14:40:04 2006 +0000
@@ -225,7 +225,7 @@
 */
 
 int ec_domain_alloc(ec_domain_t *domain, /**< EtherCAT domain */
-                    uint32_t base_address /**< Logische Basisadresse */
+                    uint32_t base_address /**< logical base address */
                     )
 {
     ec_field_reg_t *field_reg;
@@ -234,12 +234,12 @@
     unsigned int i, j, cmd_count;
     uint32_t field_off, field_off_cmd;
     uint32_t cmd_offset;
-    size_t cmd_data_size;
+    size_t cmd_data_size, sync_size;
     ec_command_t *command;
 
     domain->base_address = base_address;
 
-    // Größe der Prozessdaten berechnen und Kommandos allozieren
+    // calculate size of process data and allocate memory
     domain->data_size = 0;
     cmd_offset = base_address;
     cmd_data_size = 0;
@@ -249,20 +249,21 @@
             fmmu = &slave->fmmus[j];
             if (fmmu->domain == domain) {
                 fmmu->logical_start_address = base_address + domain->data_size;
-                domain->data_size += fmmu->sync->size;
-                if (cmd_data_size + fmmu->sync->size > EC_MAX_DATA_SIZE) {
+                sync_size = ec_slave_calc_sync_size(slave, fmmu->sync);
+                domain->data_size += sync_size;
+                if (cmd_data_size + sync_size > EC_MAX_DATA_SIZE) {
                     if (ec_domain_add_command(domain, cmd_offset,
                                               cmd_data_size)) return -1;
                     cmd_offset += cmd_data_size;
                     cmd_data_size = 0;
                     cmd_count++;
                 }
-                cmd_data_size += fmmu->sync->size;
+                cmd_data_size += sync_size;
             }
         }
     }
 
-    // Letztes Kommando allozieren
+    // allocate last command
     if (cmd_data_size) {
         if (ec_domain_add_command(domain, cmd_offset, cmd_data_size))
             return -1;
@@ -275,14 +276,14 @@
         return 0;
     }
 
-    // Alle Prozessdatenzeiger setzen
+    // set all process data pointers
     list_for_each_entry(field_reg, &domain->field_regs, list) {
         for (i = 0; i < field_reg->slave->fmmu_count; i++) {
             fmmu = &field_reg->slave->fmmus[i];
             if (fmmu->domain == domain && fmmu->sync == field_reg->sync) {
                 field_off = fmmu->logical_start_address +
                     field_reg->field_offset;
-                // Kommando suchen
+                // search command
                 list_for_each_entry(command, &domain->commands, list) {
                     field_off_cmd = field_off - command->address.logical;
                     if (field_off >= command->address.logical &&
--- a/master/fsm.c	Wed Jun 14 10:23:02 2006 +0000
+++ b/master/fsm.c	Tue Jun 20 14:40:04 2006 +0000
@@ -1128,7 +1128,7 @@
     if (slave->type) {
         for (j = 0; slave->type->sync_managers[j] && j < EC_MAX_SYNC; j++) {
             sync = slave->type->sync_managers[j];
-            ec_sync_config(sync, command->data + EC_SYNC_SIZE * j);
+            ec_sync_config(sync, slave, command->data + EC_SYNC_SIZE * j);
         }
     }
 
@@ -1247,7 +1247,8 @@
                     0x0600, EC_FMMU_SIZE * slave->base_fmmu_count);
     memset(command->data, 0x00, EC_FMMU_SIZE * slave->base_fmmu_count);
     for (j = 0; j < slave->fmmu_count; j++) {
-        ec_fmmu_config(&slave->fmmus[j], command->data + EC_FMMU_SIZE * j);
+        ec_fmmu_config(&slave->fmmus[j], slave,
+                       command->data + EC_FMMU_SIZE * j);
     }
 
     ec_master_queue_command(master, command);
--- a/master/master.c	Wed Jun 14 10:23:02 2006 +0000
+++ b/master/master.c	Tue Jun 20 14:40:04 2006 +0000
@@ -498,7 +498,7 @@
 {
     unsigned int response_tries_left;
 
-    response_tries_left = 10;
+    response_tries_left = 10000;
 
     while (1)
     {
@@ -748,11 +748,16 @@
 */
 
 void ec_sync_config(const ec_sync_t *sync, /**< sync manager */
+                    const ec_slave_t *slave, /**< EtherCAT slave */
                     uint8_t *data /**> configuration memory */
                     )
 {
+    size_t sync_size;
+
+    sync_size = ec_slave_calc_sync_size(slave, sync);
+
     EC_WRITE_U16(data,     sync->physical_start_address);
-    EC_WRITE_U16(data + 2, sync->size);
+    EC_WRITE_U16(data + 2, sync_size);
     EC_WRITE_U8 (data + 4, sync->control_byte);
     EC_WRITE_U8 (data + 5, 0x00); // status byte (read only)
     EC_WRITE_U16(data + 6, 0x0001); // enable
@@ -784,11 +789,16 @@
 */
 
 void ec_fmmu_config(const ec_fmmu_t *fmmu, /**< FMMU */
+                    const ec_slave_t *slave, /**< EtherCAT slave */
                     uint8_t *data /**> configuration memory */
                     )
 {
+    size_t sync_size;
+
+    sync_size = ec_slave_calc_sync_size(slave, fmmu->sync);
+
     EC_WRITE_U32(data,      fmmu->logical_start_address);
-    EC_WRITE_U16(data + 4,  fmmu->sync->size);
+    EC_WRITE_U16(data + 4,  sync_size); // size of fmmu
     EC_WRITE_U8 (data + 6,  0x00); // logical start bit
     EC_WRITE_U8 (data + 7,  0x07); // logical end bit
     EC_WRITE_U16(data + 8,  fmmu->sync->physical_start_address);
@@ -1133,7 +1143,8 @@
                 if (ec_command_npwr(command, slave->station_address,
                                     0x0800 + j * EC_SYNC_SIZE, EC_SYNC_SIZE))
                     return -1;
-                ec_sync_config(sync, command->data);
+                ec_sync_config(sync, slave, command->data);
+                EC_INFO("configuring sync.\n");
                 if (unlikely(ec_master_simple_io(master, command))) {
                     EC_ERR("Setting sync manager %i failed on slave %i!\n",
                            j, slave->ring_position);
@@ -1211,7 +1222,8 @@
             if (ec_command_npwr(command, slave->station_address,
                                 0x0600 + j * EC_FMMU_SIZE, EC_FMMU_SIZE))
                 return -1;
-            ec_fmmu_config(fmmu, command->data);
+            ec_fmmu_config(fmmu, slave, command->data);
+            EC_INFO("configuring fmmu.\n");
             if (unlikely(ec_master_simple_io(master, command))) {
                 EC_ERR("Setting FMMU %i failed on slave %i!\n",
                        j, slave->ring_position);
--- a/master/master.h	Wed Jun 14 10:23:02 2006 +0000
+++ b/master/master.h	Tue Jun 20 14:40:04 2006 +0000
@@ -151,9 +151,9 @@
 
 // misc.
 void ec_master_clear_slaves(ec_master_t *);
-void ec_sync_config(const ec_sync_t *, uint8_t *);
+void ec_sync_config(const ec_sync_t *, const ec_slave_t *, uint8_t *);
 void ec_eeprom_sync_config(const ec_eeprom_sync_t *, uint8_t *);
-void ec_fmmu_config(const ec_fmmu_t *, uint8_t *);
+void ec_fmmu_config(const ec_fmmu_t *, const ec_slave_t *, uint8_t *);
 void ec_master_output_stats(ec_master_t *);
 
 /*****************************************************************************/
--- a/master/slave.c	Wed Jun 14 10:23:02 2006 +0000
+++ b/master/slave.c	Tue Jun 20 14:40:04 2006 +0000
@@ -166,6 +166,7 @@
     INIT_LIST_HEAD(&slave->eeprom_syncs);
     INIT_LIST_HEAD(&slave->eeprom_pdos);
     INIT_LIST_HEAD(&slave->sdo_dictionary);
+    INIT_LIST_HEAD(&slave->varsize_fields);
 
     for (i = 0; i < 4; i++) {
         slave->dl_link[i] = 0;
@@ -192,6 +193,7 @@
     ec_eeprom_pdo_entry_t *entry, *next_ent;
     ec_sdo_t *sdo, *next_sdo;
     ec_sdo_entry_t *en, *next_en;
+    ec_varsize_t *var, *next_var;
 
     slave = container_of(kobj, ec_slave_t, kobj);
 
@@ -240,6 +242,12 @@
         kfree(sdo);
     }
 
+    // free information about variable sized data fields
+    list_for_each_entry_safe(var, next_var, &slave->varsize_fields, list) {
+        list_del(&var->list);
+        kfree(var);
+    }
+
     if (slave->eeprom_data) kfree(slave->eeprom_data);
     if (slave->new_eeprom_data) kfree(slave->new_eeprom_data);
 
@@ -1447,6 +1455,43 @@
     return -EINVAL;
 }
 
+/*****************************************************************************/
+
+/**
+   \return size of sync manager contents
+*/
+
+size_t ec_slave_calc_sync_size(const ec_slave_t *slave, /**< EtherCAT slave */
+                               const ec_sync_t *sync /**< sync manager */
+                               )
+{
+    unsigned int i, found;
+    const ec_field_t *field;
+    const ec_varsize_t *var;
+    size_t size;
+
+    // if size is specified, return size
+    if (sync->size) return sync->size;
+
+    // sync manager has variable size (size == 0).
+
+    size = 0;
+    for (i = 0; (field = sync->fields[i]); i++) {
+        found = 0;
+        list_for_each_entry(var, &slave->varsize_fields, list) {
+            if (var->field != field) continue;
+            size += var->size;
+            found = 1;
+        }
+
+        if (!found) {
+            EC_WARN("Variable data field \"%s\" of slave %i has no size"
+                    " information!\n", field->name, slave->ring_position);
+        }
+    }
+    return size;
+}
+
 /******************************************************************************
  *  Realtime interface
  *****************************************************************************/
@@ -1466,9 +1511,75 @@
 
 /*****************************************************************************/
 
+/**
+   \return 0 in case of success, else < 0
+   \ingroup RealtimeInterface
+*/
+
+int ecrt_slave_field_size(ec_slave_t *slave, /**< EtherCAT slave */
+                          const char *field_name, /**< data field name */
+                          unsigned int field_index, /**< data field index */
+                          size_t size /**< new data field size */
+                          )
+{
+    unsigned int i, j, field_counter;
+    const ec_sync_t *sync;
+    const ec_field_t *field;
+    ec_varsize_t *var;
+
+    if (!slave->type) {
+        EC_ERR("Slave %i has no type information!\n", slave->ring_position);
+        return -1;
+    }
+
+    field_counter = 0;
+    for (i = 0; (sync = slave->type->sync_managers[i]); i++) {
+        for (j = 0; (field = sync->fields[j]); j++) {
+            if (!strcmp(field->name, field_name)) {
+                if (field_counter++ == field_index) {
+                    // is the size of this field variable?
+                    if (field->size) {
+                        EC_ERR("Field \"%s\"[%i] of slave %i has no variable"
+                               " size!\n", field->name, field_index,
+                               slave->ring_position);
+                        return -1;
+                    }
+                    // does a size specification already exist?
+                    list_for_each_entry(var, &slave->varsize_fields, list) {
+                        if (var->field == field) {
+                            EC_WARN("Resizing field \"%s\"[%i] of slave %i.\n",
+                                    field->name, field_index,
+                                    slave->ring_position);
+                            var->size = size;
+                            return 0;
+                        }
+                    }
+                    // create a new size specification...
+                    if (!(var = kmalloc(sizeof(ec_varsize_t), GFP_KERNEL))) {
+                        EC_ERR("Failed to allocate memory for varsize_t!\n");
+                        return -1;
+                    }
+                    var->field = field;
+                    var->size = size;
+                    list_add_tail(&var->list, &slave->varsize_fields);
+                    return 0;
+                }
+            }
+        }
+    }
+
+    EC_ERR("Slave %i (\"%s %s\") has no field \"%s\"[%i]!\n",
+           slave->ring_position, slave->type->vendor_name,
+           slave->type->product_name, field_name, field_index);
+    return -1;
+}
+
+/*****************************************************************************/
+
 /**< \cond */
 
 EXPORT_SYMBOL(ecrt_slave_write_alias);
+EXPORT_SYMBOL(ecrt_slave_field_size);
 
 /**< \endcond */
 
--- a/master/slave.h	Wed Jun 14 10:23:02 2006 +0000
+++ b/master/slave.h	Tue Jun 20 14:40:04 2006 +0000
@@ -214,6 +214,20 @@
 /*****************************************************************************/
 
 /**
+   Variable-sized field information.
+*/
+
+typedef struct
+{
+    struct list_head list; /**< list item */
+    const ec_field_t *field; /**< data field */
+    size_t size; /**< field size */
+}
+ec_varsize_t;
+
+/*****************************************************************************/
+
+/**
    EtherCAT slave.
 */
 
@@ -282,6 +296,9 @@
     ec_slave_state_t current_state; /**< current slave state */
     unsigned int state_error; /**< a state error has happened */
     unsigned int online; /**< non-zero, if the slave responds. */
+
+    struct list_head varsize_fields; /**< size information for variable-sized
+                                        data fields. */
 };
 
 /*****************************************************************************/
@@ -310,6 +327,7 @@
 int ec_slave_locate_string(ec_slave_t *, unsigned int, char **);
 
 // misc.
+size_t ec_slave_calc_sync_size(const ec_slave_t *, const ec_sync_t *);
 void ec_slave_print(const ec_slave_t *, unsigned int);
 int ec_slave_check_crc(ec_slave_t *);
 
--- a/master/types.c	Wed Jun 14 10:23:02 2006 +0000
+++ b/master/types.c	Tue Jun 20 14:40:04 2006 +0000
@@ -67,9 +67,24 @@
 
 /*****************************************************************************/
 
+const ec_field_t bk1120_in = {"Inputs", 0}; // variable size
+
+const ec_sync_t bk1120_sm0 = {0x1C00, 264, 0x26, {NULL}};
+const ec_sync_t bk1120_sm1 = {0x1E00, 264, 0x22, {NULL}};
+
+const ec_sync_t bk1120_sm2 = { // outputs
+    0x1000, 0, 0x24, // variable size
+    {NULL}
+};
+
+const ec_sync_t bk1120_sm3 = { // inputs
+    0x1600, 0, 0x00, // variable size
+    {&bk1120_in, NULL}
+};
+
 const ec_slave_type_t Beckhoff_BK1120 = {
     "Beckhoff", "BK1120", "KBUS Coupler", EC_TYPE_NORMAL,
-    {NULL} // no sync managers
+    {&bk1120_sm0, &bk1120_sm1, &bk1120_sm2, &bk1120_sm3, NULL}
 };
 
 /*****************************************************************************/
@@ -186,8 +201,7 @@
     {&el5101_st, &el5101_ip, &el5101_la, NULL}
 };
 
-const ec_slave_type_t Beckhoff_EL5101 =
-{
+const ec_slave_type_t Beckhoff_EL5101 = {
     "Beckhoff", "EL5101", "Incremental Encoder Interface", EC_TYPE_NORMAL,
     {&mailbox_sm0, &mailbox_sm1, &el5101_sm2, &el5101_sm3, NULL}
 };
@@ -233,7 +247,7 @@
     {0x00000002, 0x03F63052, &Beckhoff_EL1014},
     {0x00000002, 0x044C2C52, &Beckhoff_EK1100},
     {0x00000002, 0x04562C52, &Beckhoff_EK1110},
-    //{0x00000002, 0x04602C22, &Beckhoff_BK1120},
+    {0x00000002, 0x04602C22, &Beckhoff_BK1120},
     {0x00000002, 0x07D43052, &Beckhoff_EL2004},
     {0x00000002, 0x07F03052, &Beckhoff_EL2032},
     {0x00000002, 0x0C1E3052, &Beckhoff_EL3102},