diff -r f149465f4c63 -r e675450f2174 master/domain.c --- a/master/domain.c Thu Jul 13 13:10:57 2006 +0000 +++ b/master/domain.c Thu Aug 03 12:59:01 2006 +0000 @@ -46,17 +46,33 @@ /*****************************************************************************/ -void ec_domain_clear_field_regs(ec_domain_t *); +/** + Data registration type. +*/ + +typedef struct +{ + struct list_head list; /**< list item */ + ec_slave_t *slave; /**< slave */ + const ec_sii_sync_t *sync; /**< sync manager */ + off_t sync_offset; /**< pdo offset */ + void **data_ptr; /**< pointer to process data pointer(s) */ +} +ec_data_reg_t; + +/*****************************************************************************/ + +void ec_domain_clear_data_regs(ec_domain_t *); ssize_t ec_show_domain_attribute(struct kobject *, struct attribute *, char *); /*****************************************************************************/ /** \cond */ -EC_SYSFS_READ_ATTR(data_size); +EC_SYSFS_READ_ATTR(image_size); static struct attribute *def_attrs[] = { - &attr_data_size, + &attr_image_size, NULL, }; @@ -91,7 +107,7 @@ domain->base_address = 0; domain->response_count = 0xFFFFFFFF; - INIT_LIST_HEAD(&domain->field_regs); + INIT_LIST_HEAD(&domain->data_regs); INIT_LIST_HEAD(&domain->datagrams); // init kobject and add it to the hierarchy @@ -127,7 +143,7 @@ kfree(datagram); } - ec_domain_clear_field_regs(domain); + ec_domain_clear_data_regs(domain); kfree(domain); } @@ -139,34 +155,70 @@ \return 0 in case of success, else < 0 */ -int ec_domain_reg_field(ec_domain_t *domain, /**< EtherCAT domain */ - ec_slave_t *slave, /**< slave */ - const ec_sync_t *sync, /**< sync manager */ - uint32_t field_offset, /**< data field offset */ - void **data_ptr /**< pointer to the process data - pointer */ - ) -{ - ec_field_reg_t *field_reg; - - if (!(field_reg = - (ec_field_reg_t *) kmalloc(sizeof(ec_field_reg_t), GFP_KERNEL))) { - EC_ERR("Failed to allocate field registration.\n"); +int ec_domain_reg_pdo_entry(ec_domain_t *domain, /**< EtherCAT domain */ + ec_slave_t *slave, /**< slave */ + const ec_sii_pdo_t *pdo, + const ec_sii_pdo_entry_t *entry, + /**< PDO registration entry */ + void **data_ptr /**< pointer to the process data + pointer */ + ) +{ + ec_data_reg_t *data_reg; + const ec_sii_sync_t *sync; + const ec_sii_pdo_t *other_pdo; + const ec_sii_pdo_entry_t *other_entry; + unsigned int bit_offset, byte_offset, sync_found; + + // Find sync manager for PDO + sync_found = 0; + list_for_each_entry(sync, &slave->sii_syncs, list) { + if (sync->index == pdo->sync_index) { + sync_found = 1; + break; + } + } + + if (!sync_found) { + EC_ERR("No sync manager for PDO 0x%04X:%i.", + pdo->index, entry->subindex); + return -1; + } + + // Calculate offset for process data pointer + bit_offset = 0; + byte_offset = 0; + list_for_each_entry(other_pdo, &slave->sii_pdos, list) { + if (other_pdo->sync_index != sync->index) continue; + + list_for_each_entry(other_entry, &pdo->entries, list) { + if (other_entry == entry) { + byte_offset = bit_offset / 8; + break; + } + bit_offset += other_entry->bit_length; + } + } + + // Allocate memory for data registration object + if (!(data_reg = + (ec_data_reg_t *) kmalloc(sizeof(ec_data_reg_t), GFP_KERNEL))) { + EC_ERR("Failed to allocate data registration.\n"); return -1; } if (ec_slave_prepare_fmmu(slave, domain, sync)) { EC_ERR("FMMU configuration failed.\n"); - kfree(field_reg); + kfree(data_reg); return -1; } - field_reg->slave = slave; - field_reg->sync = sync; - field_reg->field_offset = field_offset; - field_reg->data_ptr = data_ptr; - - list_add_tail(&field_reg->list, &domain->field_regs); + data_reg->slave = slave; + data_reg->sync = sync; + data_reg->sync_offset = byte_offset; + data_reg->data_ptr = data_ptr; + + list_add_tail(&data_reg->list, &domain->data_regs); return 0; } @@ -176,13 +228,13 @@ Clears the list of the registered data fields. */ -void ec_domain_clear_field_regs(ec_domain_t *domain /**< EtherCAT domain */) -{ - ec_field_reg_t *field_reg, *next; - - list_for_each_entry_safe(field_reg, next, &domain->field_regs, list) { - list_del(&field_reg->list); - kfree(field_reg); +void ec_domain_clear_data_regs(ec_domain_t *domain /**< EtherCAT domain */) +{ + ec_data_reg_t *data_reg, *next; + + list_for_each_entry_safe(data_reg, next, &domain->data_regs, list) { + list_del(&data_reg->list); + kfree(data_reg); } } @@ -222,7 +274,7 @@ Creates a domain. Reserves domain memory, calculates the logical addresses of the corresponding FMMUs and sets the process data pointer of the registered - data fields. + process data. \return 0 in case of success, else < 0 */ @@ -230,22 +282,22 @@ uint32_t base_address /**< logical base address */ ) { - ec_field_reg_t *field_reg; + ec_data_reg_t *data_reg; ec_slave_t *slave; ec_fmmu_t *fmmu; - unsigned int i, j, cmd_count; - uint32_t field_off, field_off_cmd; - uint32_t cmd_offset; - size_t cmd_data_size, sync_size; + unsigned int i, j, datagram_count; + uint32_t pdo_off, pdo_off_datagram; + uint32_t datagram_offset; + size_t datagram_data_size, sync_size; ec_datagram_t *datagram; domain->base_address = base_address; // calculate size of process data and allocate memory domain->data_size = 0; - cmd_offset = base_address; - cmd_data_size = 0; - cmd_count = 0; + datagram_offset = base_address; + datagram_data_size = 0; + datagram_count = 0; list_for_each_entry(slave, &domain->master->slaves, list) { for (j = 0; j < slave->fmmu_count; j++) { fmmu = &slave->fmmus[j]; @@ -253,47 +305,48 @@ fmmu->logical_start_address = base_address + domain->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_datagram(domain, cmd_offset, - cmd_data_size)) return -1; - cmd_offset += cmd_data_size; - cmd_data_size = 0; - cmd_count++; + if (datagram_data_size + sync_size > EC_MAX_DATA_SIZE) { + if (ec_domain_add_datagram(domain, datagram_offset, + datagram_data_size)) return -1; + datagram_offset += datagram_data_size; + datagram_data_size = 0; + datagram_count++; } - cmd_data_size += sync_size; + datagram_data_size += sync_size; } } } // allocate last datagram - if (cmd_data_size) { - if (ec_domain_add_datagram(domain, cmd_offset, cmd_data_size)) + if (datagram_data_size) { + if (ec_domain_add_datagram(domain, datagram_offset, + datagram_data_size)) return -1; - cmd_count++; - } - - if (!cmd_count) { + datagram_count++; + } + + if (!datagram_count) { EC_WARN("Domain %i contains no data!\n", domain->index); - ec_domain_clear_field_regs(domain); + ec_domain_clear_data_regs(domain); return 0; } // 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; + list_for_each_entry(data_reg, &domain->data_regs, list) { + for (i = 0; i < data_reg->slave->fmmu_count; i++) { + fmmu = &data_reg->slave->fmmus[i]; + if (fmmu->domain == domain && fmmu->sync == data_reg->sync) { + pdo_off = fmmu->logical_start_address + data_reg->sync_offset; // search datagram list_for_each_entry(datagram, &domain->datagrams, list) { - field_off_cmd = field_off - datagram->address.logical; - if (field_off >= datagram->address.logical && - field_off_cmd < datagram->mem_size) { - *field_reg->data_ptr = datagram->data + field_off_cmd; + pdo_off_datagram = pdo_off - datagram->address.logical; + if (pdo_off >= datagram->address.logical && + pdo_off_datagram < datagram->mem_size) { + *data_reg->data_ptr = datagram->data + + pdo_off_datagram; } } - if (!field_reg->data_ptr) { + if (!data_reg->data_ptr) { EC_ERR("Failed to assign data pointer!\n"); return -1; } @@ -303,31 +356,26 @@ } EC_INFO("Domain %i - Allocated %i bytes in %i datagram%s\n", - domain->index, domain->data_size, cmd_count, - cmd_count == 1 ? "" : "s"); - - ec_domain_clear_field_regs(domain); - - return 0; -} - -/*****************************************************************************/ - -/** - Sets the number of responding slaves and outputs it on demand. - This number isn't really the number of responding slaves, but the sum of - the working counters of all domain datagrams. Some slaves increase the - working counter by 2, some by 1. -*/ - -void ec_domain_response_count(ec_domain_t *domain, /**< EtherCAT domain */ - unsigned int count /**< new WC sum */ - ) -{ - if (count != domain->response_count) { - domain->response_count = count; - EC_INFO("Domain %i working counter change: %i\n", domain->index, - count); + domain->index, domain->data_size, datagram_count, + datagram_count == 1 ? "" : "s"); + + ec_domain_clear_data_regs(domain); + + return 0; +} + +/*****************************************************************************/ + +/** + Places all process data datagrams in the masters datagram queue. +*/ + +void ec_domain_queue(ec_domain_t *domain /**< EtherCAT domain */) +{ + ec_datagram_t *datagram; + + list_for_each_entry(datagram, &domain->datagrams, list) { + ec_master_queue_datagram(domain->master, datagram); } } @@ -345,7 +393,7 @@ { ec_domain_t *domain = container_of(kobj, ec_domain_t, kobj); - if (attr == &attr_data_size) { + if (attr == &attr_image_size) { return sprintf(buffer, "%i\n", domain->data_size); } @@ -357,62 +405,45 @@ *****************************************************************************/ /** - Registers a data field in a domain. - - If \a data_ptr is NULL, the slave is only checked against its type. - - If \a field_count is 0, it is assumed that one data field is to be - registered. - - If \a field_count is greater then 1, it is assumed that \a data_ptr - is an array of the respective size. + Registers a PDO in a domain. + - If \a data_ptr is NULL, the slave is only validated. \return pointer to the slave on success, else NULL \ingroup RealtimeInterface */ -ec_slave_t *ecrt_domain_register_field(ec_domain_t *domain, - /**< EtherCAT domain */ - const char *address, - /**< ASCII address of the slave, - see ecrt_master_get_slave() */ - const char *vendor_name, - /**< vendor name */ - const char *product_name, - /**< product name */ - void **data_ptr, - /**< address of the process data - pointer */ - const char *field_name, - /**< data field name */ - unsigned int field_index, - /**< offset of data fields with - \a field_type */ - unsigned int field_count - /**< number of data fields (with - the same type) to register */ - ) +ec_slave_t *ecrt_domain_register_pdo(ec_domain_t *domain, + /**< EtherCAT domain */ + const char *address, + /**< ASCII address of the slave, + see ecrt_master_get_slave() */ + uint32_t vendor_id, + /**< vendor ID */ + uint32_t product_code, + /**< product code */ + uint16_t pdo_index, + /**< PDO index */ + uint8_t pdo_subindex, + /**< PDO subindex */ + void **data_ptr + /**< address of the process data + pointer */ + ) { ec_slave_t *slave; - const ec_slave_type_t *type; ec_master_t *master; - const ec_sync_t *sync; - const ec_field_t *field; - unsigned int field_counter, i, j, orig_field_index, orig_field_count; - uint32_t field_offset; + const ec_sii_pdo_t *pdo; + const ec_sii_pdo_entry_t *entry; master = domain->master; // translate address if (!(slave = ecrt_master_get_slave(master, address))) return NULL; - if (!(type = slave->type)) { - EC_ERR("Slave \"%s\" (position %i) has unknown type!\n", address, - slave->ring_position); - return NULL; - } - - if (strcmp(vendor_name, type->vendor_name) || - strcmp(product_name, type->product_name)) { - EC_ERR("Invalid slave type at position %i - Requested: \"%s %s\"," - " found: \"%s %s\".\n", slave->ring_position, vendor_name, - product_name, type->vendor_name, type->product_name); + if (vendor_id != slave->sii_vendor_id || + product_code != slave->sii_product_code) { + EC_ERR("Invalid slave type at position %i - Requested: 0x%08X 0x%08X," + " found: 0x%08X 0x%08X\".\n", slave->ring_position, vendor_id, + product_code, slave->sii_vendor_id, slave->sii_product_code); return NULL; } @@ -421,32 +452,22 @@ slave->registered = 1; } - if (!field_count) field_count = 1; - orig_field_index = field_index; - orig_field_count = field_count; - - field_counter = 0; - for (i = 0; type->sync_managers[i]; i++) { - sync = type->sync_managers[i]; - field_offset = 0; - for (j = 0; sync->fields[j]; j++) { - field = sync->fields[j]; - if (!strcmp(field->name, field_name)) { - if (field_counter++ == field_index) { - if (data_ptr) - ec_domain_reg_field(domain, slave, sync, field_offset, - data_ptr++); - if (!(--field_count)) return slave; - field_index++; - } + list_for_each_entry(pdo, &slave->sii_pdos, list) { + list_for_each_entry(entry, &pdo->entries, list) { + if (entry->index != pdo_index + || entry->subindex != pdo_subindex) continue; + + if (data_ptr) { + ec_domain_reg_pdo_entry(domain, slave, pdo, entry, data_ptr); } - field_offset += field->size; + + return slave; } } - EC_ERR("Slave %i (\"%s %s\") registration mismatch: Field \"%s\"," - " index %i, count %i.\n", slave->ring_position, vendor_name, - product_name, field_name, orig_field_index, orig_field_count); + EC_ERR("Slave %i does not provide PDO 0x%04X:%i.\n", + slave->ring_position, pdo_index, pdo_subindex); + slave->registered = 0; return NULL; } @@ -459,20 +480,21 @@ \ingroup RealtimeInterface */ -int ecrt_domain_register_field_list(ec_domain_t *domain, - /**< EtherCAT domain */ - const ec_field_init_t *fields - /**< array of data field registrations */ - ) -{ - const ec_field_init_t *field; - - for (field = fields; field->slave_address; field++) - if (!ecrt_domain_register_field(domain, field->slave_address, - field->vendor_name, - field->product_name, field->data_ptr, - field->field_name, field->field_index, - field->field_count)) +int ecrt_domain_register_pdo_list(ec_domain_t *domain, + /**< EtherCAT domain */ + const ec_pdo_reg_t *pdos + /**< array of PDO registrations */ + ) +{ + const ec_pdo_reg_t *pdo; + + for (pdo = pdos; pdo->slave_address; pdo++) + if (!ecrt_domain_register_pdo(domain, pdo->slave_address, + pdo->vendor_id, + pdo->product_code, + pdo->pdo_index, + pdo->pdo_subindex, + pdo->data_ptr)) return -1; return 0; @@ -481,23 +503,7 @@ /*****************************************************************************/ /** - Places all process data datagrams in the masters datagram queue. - \ingroup RealtimeInterface -*/ - -void ecrt_domain_queue(ec_domain_t *domain /**< EtherCAT domain */) -{ - ec_datagram_t *datagram; - - list_for_each_entry(datagram, &domain->datagrams, list) { - ec_master_queue_datagram(domain->master, datagram); - } -} - -/*****************************************************************************/ - -/** - Processes received process data. + Processes received process data and requeues the domain datagram(s). \ingroup RealtimeInterface */ @@ -507,14 +513,19 @@ ec_datagram_t *datagram; working_counter_sum = 0; - list_for_each_entry(datagram, &domain->datagrams, list) { - if (datagram->state == EC_CMD_RECEIVED) { + if (datagram->state == EC_DATAGRAM_RECEIVED) { working_counter_sum += datagram->working_counter; } } - ec_domain_response_count(domain, working_counter_sum); + if (working_counter_sum != domain->response_count) { + domain->response_count = working_counter_sum; + EC_INFO("Domain %i working counter change: %i\n", domain->index, + domain->response_count); + } + + ec_domain_queue(domain); } /*****************************************************************************/ @@ -525,12 +536,12 @@ \ingroup RealtimeInterface */ -int ecrt_domain_state(ec_domain_t *domain /**< EtherCAT domain */) +int ecrt_domain_state(const ec_domain_t *domain /**< EtherCAT domain */) { ec_datagram_t *datagram; list_for_each_entry(datagram, &domain->datagrams, list) { - if (datagram->state != EC_CMD_RECEIVED) return -1; + if (datagram->state != EC_DATAGRAM_RECEIVED) return -1; } return 0; @@ -540,9 +551,8 @@ /** \cond */ -EXPORT_SYMBOL(ecrt_domain_register_field); -EXPORT_SYMBOL(ecrt_domain_register_field_list); -EXPORT_SYMBOL(ecrt_domain_queue); +EXPORT_SYMBOL(ecrt_domain_register_pdo); +EXPORT_SYMBOL(ecrt_domain_register_pdo_list); EXPORT_SYMBOL(ecrt_domain_process); EXPORT_SYMBOL(ecrt_domain_state);