From 23ad81a414f5a8a720bf6b3965ef469dec3df6c6 Mon Sep 17 00:00:00 2001 From: Florian Pose <fp@igh-essen.com> Date: Tue, 20 Jun 2006 14:40:04 +0000 Subject: [PATCH] Variable-sized data fields, BK1120. --- examples/mini/mini.c | 23 +++++---- include/ecrt.h | 5 +- master/domain.c | 19 ++++---- master/fsm.c | 5 +- master/master.c | 22 +++++++-- master/master.h | 4 +- master/slave.c | 111 +++++++++++++++++++++++++++++++++++++++++++ master/slave.h | 18 +++++++ master/types.c | 22 +++++++-- 9 files changed, 196 insertions(+), 33 deletions(-) diff --git a/examples/mini/mini.c b/examples/mini/mini.c index 46093c77..0cc05cf7 100644 --- a/examples/mini/mini.c +++ b/examples/mini/mini.c @@ -57,14 +57,14 @@ spinlock_t master_lock = SPIN_LOCK_UNLOCKED; // 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 @@ void release_lock(void *data) 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 @@ int __init init_mini_module(void) 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 @@ int __init init_mini_module(void) } #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); diff --git a/include/ecrt.h b/include/ecrt.h index 00366993..8416c172 100644 --- a/include/ecrt.h +++ b/include/ecrt.h @@ -160,7 +160,10 @@ int ecrt_slave_sdo_write_exp32(ec_slave_t *slave, uint16_t sdo_index, 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 diff --git a/master/domain.c b/master/domain.c index 5038c707..db8c026e 100644 --- a/master/domain.c +++ b/master/domain.c @@ -225,7 +225,7 @@ int ec_domain_add_command(ec_domain_t *domain, /**< EtherCAT domain */ */ 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 @@ int ec_domain_alloc(ec_domain_t *domain, /**< EtherCAT domain */ 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 @@ int ec_domain_alloc(ec_domain_t *domain, /**< EtherCAT domain */ 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 @@ int ec_domain_alloc(ec_domain_t *domain, /**< EtherCAT domain */ 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 && diff --git a/master/fsm.c b/master/fsm.c index 93147597..8162b68e 100644 --- a/master/fsm.c +++ b/master/fsm.c @@ -1128,7 +1128,7 @@ void ec_fsm_slave_sync(ec_fsm_t *fsm /**< finite state machine */) 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 @@ void ec_fsm_slave_fmmu(ec_fsm_t *fsm /**< finite state machine */) 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); diff --git a/master/master.c b/master/master.c index 46d94fe4..a33566ff 100644 --- a/master/master.c +++ b/master/master.c @@ -498,7 +498,7 @@ int ec_master_simple_io(ec_master_t *master, /**< EtherCAT master */ { unsigned int response_tries_left; - response_tries_left = 10; + response_tries_left = 10000; while (1) { @@ -748,11 +748,16 @@ void ec_master_freerun(void *data /**< master pointer */) */ 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_eeprom_sync_config(const ec_eeprom_sync_t *sync, /**< sync manager */ */ 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 @@ int ecrt_master_activate(ec_master_t *master /**< EtherCAT master */) 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 @@ int ecrt_master_activate(ec_master_t *master /**< EtherCAT master */) 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); diff --git a/master/master.h b/master/master.h index 543417c4..8bbb1880 100644 --- a/master/master.h +++ b/master/master.h @@ -151,9 +151,9 @@ int ec_master_bus_scan(ec_master_t *); // 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 *); /*****************************************************************************/ diff --git a/master/slave.c b/master/slave.c index dc96afff..06b2a748 100644 --- a/master/slave.c +++ b/master/slave.c @@ -166,6 +166,7 @@ int ec_slave_init(ec_slave_t *slave, /**< EtherCAT slave */ 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 @@ void ec_slave_clear(struct kobject *kobj /**< kobject of the slave */) 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 @@ void ec_slave_clear(struct kobject *kobj /**< kobject of the slave */) 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 @@ ssize_t ec_store_slave_attribute(struct kobject *kobj, /**< slave's kobject */ 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 @@ int ecrt_slave_write_alias(ec_slave_t *slave, /**< EtherCAT slave */ /*****************************************************************************/ +/** + \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 */ diff --git a/master/slave.h b/master/slave.h index 576910e7..e6ef8431 100644 --- a/master/slave.h +++ b/master/slave.h @@ -213,6 +213,20 @@ ec_sdo_entry_t; /*****************************************************************************/ +/** + 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 @@ struct ec_slave 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_fetch_pdo(ec_slave_t *, const uint8_t *, size_t, ec_pdo_type_t); 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 *); diff --git a/master/types.c b/master/types.c index 255cb51d..6e6271a5 100644 --- a/master/types.c +++ b/master/types.c @@ -67,9 +67,24 @@ const ec_slave_type_t Beckhoff_EK1110 = { /*****************************************************************************/ +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 @@ const ec_sync_t el5101_sm3 = { {&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 @@ ec_slave_ident_t slave_idents[] = { {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}, -- GitLab