# HG changeset patch # User Florian Pose # Date 1150814404 0 # Node ID ba51285d4ef6eaa78fe40692dbc398547940d715 # Parent b397aee6e602408ec75cbea87e2479be9e741815 Variable-sized data fields, BK1120. diff -r b397aee6e602 -r ba51285d4ef6 examples/mini/mini.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); diff -r b397aee6e602 -r ba51285d4ef6 include/ecrt.h --- 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 diff -r b397aee6e602 -r ba51285d4ef6 master/domain.c --- 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 && diff -r b397aee6e602 -r ba51285d4ef6 master/fsm.c --- 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); diff -r b397aee6e602 -r ba51285d4ef6 master/master.c --- 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); diff -r b397aee6e602 -r ba51285d4ef6 master/master.h --- 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 *); /*****************************************************************************/ diff -r b397aee6e602 -r ba51285d4ef6 master/slave.c --- 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 */ diff -r b397aee6e602 -r ba51285d4ef6 master/slave.h --- 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 *); diff -r b397aee6e602 -r ba51285d4ef6 master/types.c --- 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},