master/master.c
changeset 640 16e9ad7d8e12
parent 639 aa23c48dca2d
child 643 78929d878b2c
--- a/master/master.c	Thu Mar 08 18:15:25 2007 +0000
+++ b/master/master.c	Fri Mar 09 10:24:50 2007 +0000
@@ -1384,215 +1384,24 @@
     }
 }
 
-/******************************************************************************
- *  Realtime interface
- *****************************************************************************/
-
-/**
-   Creates a domain.
-   \return pointer to new domain on success, else NULL
-   \ingroup RealtimeInterface
-*/
-
-ec_domain_t *ecrt_master_create_domain(ec_master_t *master /**< master */)
-{
-    ec_domain_t *domain, *last_domain;
-    unsigned int index;
-
-    if (!(domain = (ec_domain_t *) kmalloc(sizeof(ec_domain_t), GFP_KERNEL))) {
-        EC_ERR("Error allocating domain memory!\n");
-        return NULL;
-    }
-
-    if (list_empty(&master->domains)) index = 0;
-    else {
-        last_domain = list_entry(master->domains.prev, ec_domain_t, list);
-        index = last_domain->index + 1;
-    }
-
-    if (ec_domain_init(domain, master, index)) {
-        EC_ERR("Failed to init domain.\n");
-        return NULL;
-    }
-
-    list_add_tail(&domain->list, &master->domains);
-
-    return domain;
-}
-
-/*****************************************************************************/
-
-/**
-   Configures all slaves and leads them to the OP state.
-   Does the complete configuration and activation for all slaves. Sets sync
-   managers and FMMUs, and does the appropriate transitions, until the slave
-   is operational.
-   \return 0 in case of success, else < 0
-   \ingroup RealtimeInterface
-*/
-
-int ecrt_master_activate(ec_master_t *master /**< EtherCAT master */)
-{
-    uint32_t domain_offset;
-    ec_domain_t *domain;
-    ec_fsm_slave_t fsm_slave;
-    ec_slave_t *slave;
-
-    // allocate all domains
-    domain_offset = 0;
-    list_for_each_entry(domain, &master->domains, list) {
-        if (ec_domain_alloc(domain, domain_offset)) {
-            EC_ERR("Failed to allocate domain %X!\n", (u32) domain);
-            return -1;
-        }
-        domain_offset += domain->data_size;
-    }
-
-    ec_fsm_slave_init(&fsm_slave, &master->fsm_datagram);
-
-    // configure all slaves
-    list_for_each_entry(slave, &master->slaves, list) {
-        ec_fsm_slave_start_conf(&fsm_slave, slave);
-        while (ec_fsm_slave_exec(&fsm_slave)) { 
-            ec_master_queue_datagram(master, &master->fsm_datagram);
-            ec_master_sync_io(master);
-        }
-
-        if (!ec_fsm_slave_success(&fsm_slave)) {
-            ec_fsm_slave_clear(&fsm_slave);
-            EC_ERR("Failed to configure slave %i!\n", slave->ring_position);
-            return -1;
-        }
-    }
-
-    ec_fsm_slave_clear(&fsm_slave);
-    ec_master_prepare(master); // prepare asynchronous IO
-
-    if (master->debug_level)
-        EC_DBG("FSM datagram is %x.\n", (unsigned int) &master->fsm_datagram);
-
-    if (ec_master_thread_start(master)) {
-        EC_ERR("Failed to start master thread!\n");
-        return -1;
-    }
-
-    return 0;
-}
-
-/*****************************************************************************/
-
-/**
-   Sends queued datagrams and waits for their reception.
-*/
-
-void ec_master_sync_io(ec_master_t *master /**< EtherCAT master */)
-{
-    ec_datagram_t *datagram;
-    unsigned int datagrams_sent;
-
-    // send all datagrams
-    ecrt_master_send(master);
-
-    while (1) { // active waiting
-        schedule(); // schedule other processes while waiting.
-        ecrt_master_receive(master); // receive and dequeue datagrams
-
-        // count number of datagrams still waiting for response
-        datagrams_sent = 0;
-        list_for_each_entry(datagram, &master->datagram_queue, queue) {
-            // there may be another process that queued commands
-            // in the meantime.
-            if (datagram->state == EC_DATAGRAM_QUEUED) continue;
-            datagrams_sent++;
-        }
-
-        // abort loop if there are no more datagrams marked as sent.
-        if (!datagrams_sent) break;
-    }
-}
-
-/*****************************************************************************/
-
-/**
-   Asynchronous sending of datagrams.
-   \ingroup RealtimeInterface
-*/
-
-void ecrt_master_send(ec_master_t *master /**< EtherCAT master */)
-{
-    ec_datagram_t *datagram, *n;
-
-    if (master->injection_seq_rt != master->injection_seq_fsm) {
-        // inject datagram produced by master FSM
-        ec_master_queue_datagram(master, &master->fsm_datagram);
-        master->injection_seq_rt = master->injection_seq_fsm;
-    }
-
-    if (unlikely(!master->main_device.link_state)) {
-        // link is down, no datagram can be sent
-        list_for_each_entry_safe(datagram, n, &master->datagram_queue, queue) {
-            datagram->state = EC_DATAGRAM_ERROR;
-            list_del_init(&datagram->queue);
-        }
-
-        // query link state
-        ec_device_poll(&master->main_device);
-        return;
-    }
-
-    // send frames
-    ec_master_send_datagrams(master);
-}
-
-/*****************************************************************************/
-
-/**
-   Asynchronous receiving of datagrams.
-   \ingroup RealtimeInterface
-*/
-
-void ecrt_master_receive(ec_master_t *master /**< EtherCAT master */)
-{
-    ec_datagram_t *datagram, *next;
-    cycles_t cycles_timeout;
-
-    // receive datagrams
-    ec_device_poll(&master->main_device);
-
-    cycles_timeout = (cycles_t) EC_IO_TIMEOUT /* us */ * (cpu_khz / 1000);
-
-    // dequeue all datagrams that timed out
-    list_for_each_entry_safe(datagram, next, &master->datagram_queue, queue) {
-        if (datagram->state != EC_DATAGRAM_SENT) continue;
-
-        if (master->main_device.cycles_poll - datagram->cycles_sent
-            > cycles_timeout) {
-            list_del_init(&datagram->queue);
-            datagram->state = EC_DATAGRAM_TIMED_OUT;
-            master->stats.timeouts++;
-            ec_master_output_stats(master);
-        }
-    }
-}
-
-/*****************************************************************************/
-
-/**
-   Translates an ASCII coded bus-address to a slave pointer.
-   These are the valid addressing schemes:
-   - \a "X" = the X. slave on the bus,
-   - \a "X:Y" = the Y. slave after the X. branch (bus coupler),
-   - \a "#X" = the slave with alias X,
-   - \a "#X:Y" = the Y. slave after the branch (bus coupler) with alias X.
-   X and Y are zero-based indices and may be provided in hexadecimal or octal
-   notation (with respective prefix).
-   \return pointer to the slave on success, else NULL
-   \ingroup RealtimeInterface
-*/
-
-ec_slave_t *ecrt_master_get_slave(const ec_master_t *master, /**< Master */
-                                  const char *address /**< address string */
-                                  )
+/*****************************************************************************/
+
+/**
+ * Translates an ASCII coded bus-address to a slave pointer.
+ * These are the valid addressing schemes:
+ * - \a "X" = the X. slave on the bus (ring position),
+ * - \a "X:Y" = the Y. slave after the X. branch (bus coupler),
+ * - \a "#X" = the slave with alias X,
+ * - \a "#X:Y" = the Y. slave after the branch (bus coupler) with alias X.
+ * X and Y are zero-based indices and may be provided in hexadecimal or octal
+ * notation (with respective prefix).
+ * \return pointer to the slave on success, else NULL
+ */
+
+ec_slave_t *ec_master_parse_slave_address(
+        const ec_master_t *master, /**< EtherCAT master */
+        const char *address /**< address string */
+        )
 {
     unsigned long first, second;
     char *remainder, *remainder2;
@@ -1685,6 +1494,224 @@
     return NULL;
 }
 
+
+/******************************************************************************
+ *  Realtime interface
+ *****************************************************************************/
+
+/**
+   Creates a domain.
+   \return pointer to new domain on success, else NULL
+   \ingroup RealtimeInterface
+*/
+
+ec_domain_t *ecrt_master_create_domain(ec_master_t *master /**< master */)
+{
+    ec_domain_t *domain, *last_domain;
+    unsigned int index;
+
+    if (!(domain = (ec_domain_t *) kmalloc(sizeof(ec_domain_t), GFP_KERNEL))) {
+        EC_ERR("Error allocating domain memory!\n");
+        return NULL;
+    }
+
+    if (list_empty(&master->domains)) index = 0;
+    else {
+        last_domain = list_entry(master->domains.prev, ec_domain_t, list);
+        index = last_domain->index + 1;
+    }
+
+    if (ec_domain_init(domain, master, index)) {
+        EC_ERR("Failed to init domain.\n");
+        return NULL;
+    }
+
+    list_add_tail(&domain->list, &master->domains);
+
+    return domain;
+}
+
+/*****************************************************************************/
+
+/**
+   Configures all slaves and leads them to the OP state.
+   Does the complete configuration and activation for all slaves. Sets sync
+   managers and FMMUs, and does the appropriate transitions, until the slave
+   is operational.
+   \return 0 in case of success, else < 0
+   \ingroup RealtimeInterface
+*/
+
+int ecrt_master_activate(ec_master_t *master /**< EtherCAT master */)
+{
+    uint32_t domain_offset;
+    ec_domain_t *domain;
+    ec_fsm_slave_t fsm_slave;
+    ec_slave_t *slave;
+
+    // allocate all domains
+    domain_offset = 0;
+    list_for_each_entry(domain, &master->domains, list) {
+        if (ec_domain_alloc(domain, domain_offset)) {
+            EC_ERR("Failed to allocate domain %X!\n", (u32) domain);
+            return -1;
+        }
+        domain_offset += domain->data_size;
+    }
+
+    ec_fsm_slave_init(&fsm_slave, &master->fsm_datagram);
+
+    // configure all slaves
+    list_for_each_entry(slave, &master->slaves, list) {
+        ec_fsm_slave_start_conf(&fsm_slave, slave);
+        while (ec_fsm_slave_exec(&fsm_slave)) { 
+            ec_master_queue_datagram(master, &master->fsm_datagram);
+            ec_master_sync_io(master);
+        }
+
+        if (!ec_fsm_slave_success(&fsm_slave)) {
+            ec_fsm_slave_clear(&fsm_slave);
+            EC_ERR("Failed to configure slave %i!\n", slave->ring_position);
+            return -1;
+        }
+    }
+
+    ec_fsm_slave_clear(&fsm_slave);
+    ec_master_prepare(master); // prepare asynchronous IO
+
+    if (master->debug_level)
+        EC_DBG("FSM datagram is %x.\n", (unsigned int) &master->fsm_datagram);
+
+    if (ec_master_thread_start(master)) {
+        EC_ERR("Failed to start master thread!\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+/*****************************************************************************/
+
+/**
+   Sends queued datagrams and waits for their reception.
+*/
+
+void ec_master_sync_io(ec_master_t *master /**< EtherCAT master */)
+{
+    ec_datagram_t *datagram;
+    unsigned int datagrams_sent;
+
+    // send all datagrams
+    ecrt_master_send(master);
+
+    while (1) { // active waiting
+        schedule(); // schedule other processes while waiting.
+        ecrt_master_receive(master); // receive and dequeue datagrams
+
+        // count number of datagrams still waiting for response
+        datagrams_sent = 0;
+        list_for_each_entry(datagram, &master->datagram_queue, queue) {
+            // there may be another process that queued commands
+            // in the meantime.
+            if (datagram->state == EC_DATAGRAM_QUEUED) continue;
+            datagrams_sent++;
+        }
+
+        // abort loop if there are no more datagrams marked as sent.
+        if (!datagrams_sent) break;
+    }
+}
+
+/*****************************************************************************/
+
+/**
+   Asynchronous sending of datagrams.
+   \ingroup RealtimeInterface
+*/
+
+void ecrt_master_send(ec_master_t *master /**< EtherCAT master */)
+{
+    ec_datagram_t *datagram, *n;
+
+    if (master->injection_seq_rt != master->injection_seq_fsm) {
+        // inject datagram produced by master FSM
+        ec_master_queue_datagram(master, &master->fsm_datagram);
+        master->injection_seq_rt = master->injection_seq_fsm;
+    }
+
+    if (unlikely(!master->main_device.link_state)) {
+        // link is down, no datagram can be sent
+        list_for_each_entry_safe(datagram, n, &master->datagram_queue, queue) {
+            datagram->state = EC_DATAGRAM_ERROR;
+            list_del_init(&datagram->queue);
+        }
+
+        // query link state
+        ec_device_poll(&master->main_device);
+        return;
+    }
+
+    // send frames
+    ec_master_send_datagrams(master);
+}
+
+/*****************************************************************************/
+
+/**
+   Asynchronous receiving of datagrams.
+   \ingroup RealtimeInterface
+*/
+
+void ecrt_master_receive(ec_master_t *master /**< EtherCAT master */)
+{
+    ec_datagram_t *datagram, *next;
+    cycles_t cycles_timeout;
+
+    // receive datagrams
+    ec_device_poll(&master->main_device);
+
+    cycles_timeout = (cycles_t) EC_IO_TIMEOUT /* us */ * (cpu_khz / 1000);
+
+    // dequeue all datagrams that timed out
+    list_for_each_entry_safe(datagram, next, &master->datagram_queue, queue) {
+        if (datagram->state != EC_DATAGRAM_SENT) continue;
+
+        if (master->main_device.cycles_poll - datagram->cycles_sent
+            > cycles_timeout) {
+            list_del_init(&datagram->queue);
+            datagram->state = EC_DATAGRAM_TIMED_OUT;
+            master->stats.timeouts++;
+            ec_master_output_stats(master);
+        }
+    }
+}
+
+/*****************************************************************************/
+
+/**
+ * Obtains a slave pointer by its bus address.
+ * A valid slave pointer is only returned, if vendor ID and product code are
+ * matching.
+ * \return pointer to the slave on success, else NULL
+ * \ingroup RealtimeInterface
+ */
+
+ec_slave_t *ecrt_master_get_slave(
+        const ec_master_t *master, /**< EtherCAT master */
+        const char *address, /**< address string
+                               \see ec_master_parse_slave_address() */
+        uint32_t vendor_id, /**< vendor ID */
+        uint32_t product_code /**< product code */
+        )
+{
+    ec_slave_t *slave = ec_master_parse_slave_address(master, address);
+
+    if (!slave)
+        return NULL;
+
+    return ec_slave_validate(slave, vendor_id, product_code) ? NULL : slave;
+}
+
 /*****************************************************************************/
 
 /**