master/domain.c
branchstable-1.1
changeset 1732 1cc865ba17c2
parent 1728 4cf9c3e9f0bd
child 1739 5fcbd29151d2
--- a/master/domain.c	Fri Oct 13 10:07:10 2006 +0000
+++ b/master/domain.c	Tue Nov 07 12:13:30 2006 +0000
@@ -62,6 +62,7 @@
 
 /*****************************************************************************/
 
+void ec_domain_clear(struct kobject *);
 void ec_domain_clear_data_regs(ec_domain_t *);
 ssize_t ec_show_domain_attribute(struct kobject *, struct attribute *, char *);
 
@@ -119,6 +120,12 @@
     domain->kobj.parent = &master->kobj;
     if (kobject_set_name(&domain->kobj, "domain%i", index)) {
         EC_ERR("Failed to set kobj name.\n");
+        kobject_put(&domain->kobj);
+        return -1;
+    }
+    if (kobject_add(&domain->kobj)) {
+        EC_ERR("Failed to add domain kobject.\n");
+        kobject_put(&domain->kobj);
         return -1;
     }
 
@@ -129,6 +136,30 @@
 
 /**
    Domain destructor.
+   Clears and frees a domain object.
+*/
+
+void ec_domain_destroy(ec_domain_t *domain /**< EtherCAT domain */)
+{
+    ec_datagram_t *datagram;
+
+    // dequeue datagrams
+    list_for_each_entry(datagram, &domain->datagrams, list) {
+        if (!list_empty(&datagram->queue)) // datagram queued?
+            list_del_init(&datagram->queue);
+    }
+
+    // destroy self
+    kobject_del(&domain->kobj);
+    kobject_put(&domain->kobj);
+}
+
+/*****************************************************************************/
+
+/**
+   Clear and free domain.
+   This method is called by the kobject,
+   once there are no more references to it.
 */
 
 void ec_domain_clear(struct kobject *kobj /**< kobject of the domain */)
@@ -138,8 +169,6 @@
 
     domain = container_of(kobj, ec_domain_t, kobj);
 
-    EC_INFO("Clearing domain %i.\n", domain->index);
-
     list_for_each_entry_safe(datagram, next, &domain->datagrams, list) {
         ec_datagram_clear(datagram);
         kfree(datagram);
@@ -187,7 +216,7 @@
         return -1;
     }
 
-    // Calculate offset for process data pointer
+    // Calculate offset (in sync manager) for process data pointer
     bit_offset = 0;
     byte_offset = 0;
     list_for_each_entry(other_pdo, &slave->sii_pdos, list) {
@@ -221,6 +250,87 @@
     data_reg->data_ptr = data_ptr;
 
     list_add_tail(&data_reg->list, &domain->data_regs);
+
+    ec_slave_request_state(slave, EC_SLAVE_STATE_OP);
+
+    return 0;
+}
+
+/*****************************************************************************/
+
+/**
+   Registeres a PDO range.
+   \return 0 in case of success, else < 0
+*/
+
+int ec_domain_reg_pdo_range(ec_domain_t *domain, /**< EtherCAT domain */
+                            ec_slave_t *slave, /**< slave */
+                            ec_direction_t dir, /**< data direction */
+                            uint16_t offset, /**< offset */
+                            uint16_t length, /**< length */
+                            void **data_ptr /**< pointer to the process data
+                                               pointer */
+                            )
+{
+    ec_data_reg_t *data_reg;
+    ec_sii_sync_t *sync;
+    unsigned int sync_found, sync_index;
+    uint16_t sync_length;
+
+    switch (dir) {
+        case EC_DIR_OUTPUT: sync_index = 2; break;
+        case EC_DIR_INPUT:  sync_index = 3; break;
+        default:
+            EC_ERR("Invalid direction!\n");
+            return -1;
+    }
+
+    // Find sync manager
+    sync_found = 0;
+    list_for_each_entry(sync, &slave->sii_syncs, list) {
+        if (sync->index == sync_index) {
+            sync_found = 1;
+            break;
+        }
+    }
+
+    if (!sync_found) {
+        EC_ERR("No sync manager found for PDO range.\n");
+        return -1;
+    }
+
+     // 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(data_reg);
+        return -1;
+    }
+
+    data_reg->slave = slave;
+    data_reg->sync = sync;
+    data_reg->sync_offset = offset;
+    data_reg->data_ptr = data_ptr;
+
+    // estimate sync manager length
+    sync_length = offset + length;
+    if (sync->est_length < sync_length) {
+        sync->est_length = sync_length;
+        if (domain->master->debug_level) {
+            EC_DBG("Estimating length of sync manager %i of slave %i to %i.\n",
+                   sync->index, slave->ring_position, sync_length);
+        }
+    }
+
+    list_add_tail(&data_reg->list, &domain->data_regs);
+
+    ec_slave_request_state(slave, EC_SLAVE_STATE_OP);
+
     return 0;
 }
 
@@ -372,7 +482,7 @@
    Places all process data datagrams in the masters datagram queue.
 */
 
-void ec_domain_queue(ec_domain_t *domain /**< EtherCAT domain */)
+void ec_domain_queue_datagrams(ec_domain_t *domain /**< EtherCAT domain */)
 {
     ec_datagram_t *datagram;
 
@@ -438,29 +548,19 @@
 
     master = domain->master;
 
-    // translate address
+    // translate address and validate slave
     if (!(slave = ecrt_master_get_slave(master, address))) return NULL;
-
-    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;
-    }
-
-    if (!data_ptr) {
-        // data_ptr is NULL => mark slave as "registered" (do not warn)
-        slave->registered = 1;
-    }
+    if (ec_slave_validate(slave, vendor_id, product_code)) return NULL;
+
+    if (!data_ptr) return slave;
 
     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);
+            if (ec_domain_reg_pdo_entry(domain, slave, pdo, entry, data_ptr)) {
+                return NULL;
             }
 
             return slave;
@@ -469,7 +569,6 @@
 
     EC_ERR("Slave %i does not provide PDO 0x%04X:%i.\n",
            slave->ring_position, pdo_index, pdo_subindex);
-    slave->registered = 0;
     return NULL;
 }
 
@@ -505,6 +604,54 @@
 /*****************************************************************************/
 
 /**
+   Registers a PDO range 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_pdo_range(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 */
+                                           ec_direction_t direction,
+                                           /**< data direction */
+                                           uint16_t offset,
+                                           /**< offset in slave's PDO range */
+                                           uint16_t length,
+                                           /**< length of this range */
+                                           void **data_ptr
+                                           /**< address of the process data
+                                              pointer */
+                                           )
+{
+    ec_slave_t *slave;
+    ec_master_t *master;
+
+    master = domain->master;
+
+    // translate address and validate slave
+    if (!(slave = ecrt_master_get_slave(master, address))) return NULL;
+    if (ec_slave_validate(slave, vendor_id, product_code)) return NULL;
+
+    if (!data_ptr) return slave;
+
+    if (ec_domain_reg_pdo_range(domain, slave,
+                                direction, offset, length, data_ptr)) {
+        return NULL;
+    }
+
+    return slave;
+}
+
+/*****************************************************************************/
+
+/**
    Processes received process data and requeues the domain datagram(s).
    \ingroup RealtimeInterface
 */
@@ -545,7 +692,7 @@
         domain->working_counter_changes = 0;
     }
 
-    ec_domain_queue(domain);
+    ec_domain_queue_datagrams(domain);
 }
 
 /*****************************************************************************/
@@ -567,6 +714,7 @@
 
 EXPORT_SYMBOL(ecrt_domain_register_pdo);
 EXPORT_SYMBOL(ecrt_domain_register_pdo_list);
+EXPORT_SYMBOL(ecrt_domain_register_pdo_range);
 EXPORT_SYMBOL(ecrt_domain_process);
 EXPORT_SYMBOL(ecrt_domain_state);