master/master.c
changeset 1583 017fa8fd9ac1
parent 1580 1baac79a40cf
child 1585 1f640e321ee4
--- a/master/master.c	Mon Nov 23 14:22:48 2009 +0100
+++ b/master/master.c	Thu Nov 26 15:33:48 2009 +0100
@@ -151,6 +151,8 @@
     INIT_LIST_HEAD(&master->ext_datagram_queue);
     sema_init(&master->ext_queue_sem, 1);
 
+    INIT_LIST_HEAD(&master->sdo_datagram_queue);
+
     INIT_LIST_HEAD(&master->domains);
 
     master->debug_level = debug_level;
@@ -684,6 +686,39 @@
     master->phase = EC_IDLE;
 }
 
+
+/*****************************************************************************/
+
+/** Injects sdo datagrams that fit into the datagram queue
+ */
+void ec_master_inject_sdo_datagrams(
+        ec_master_t *master /**< EtherCAT master */
+        )
+{
+    ec_datagram_t *sdo_datagram, *n;
+    list_for_each_entry_safe(sdo_datagram, n, &master->sdo_datagram_queue, queue) {
+        list_del_init(&sdo_datagram->queue);
+        if (master->debug_level)
+            EC_DBG("queuing SDO datagram %08x\n",(unsigned int)sdo_datagram);
+        ec_master_queue_datagram(master, sdo_datagram);
+    }
+}
+
+/*****************************************************************************/
+
+/** Places a sdo datagram in the sdo datagram queue.
+ */
+void ec_master_queue_sdo_datagram(
+        ec_master_t *master, /**< EtherCAT master */
+        ec_datagram_t *datagram /**< datagram */
+        )
+{
+    down(&master->io_sem);
+    list_add_tail(&datagram->queue, &master->sdo_datagram_queue);
+    datagram->state = EC_DATAGRAM_QUEUED;
+    up(&master->io_sem);
+}
+
 /*****************************************************************************/
 
 /** Places a datagram in the datagram queue.
@@ -695,6 +730,8 @@
 {
     ec_datagram_t *queued_datagram;
 
+    if (datagram->state == EC_DATAGRAM_SENT)
+        return;
     // check, if the datagram is already queued
     list_for_each_entry(queued_datagram, &master->datagram_queue, queue) {
         if (queued_datagram == datagram) {
@@ -1001,7 +1038,8 @@
 static int ec_master_idle_thread(void *priv_data)
 {
     ec_master_t *master = (ec_master_t *) priv_data;
-
+    ec_slave_t *slave = NULL;
+    int fsm_exec;
     if (master->debug_level)
         EC_DBG("Idle thread running.\n");
 
@@ -1013,22 +1051,27 @@
         ecrt_master_receive(master);
         up(&master->io_sem);
 
-        if (master->fsm_datagram.state == EC_DATAGRAM_SENT)
-            goto schedule;
-
-        // execute master state machine
+        fsm_exec = 0;
+        // execute master & slave state machines
         if (down_interruptible(&master->master_sem))
             break;
-        ec_fsm_master_exec(&master->fsm);
+        fsm_exec = ec_fsm_master_exec(&master->fsm);
+        for (slave = master->slaves;
+                slave < master->slaves + master->slave_count;
+                slave++) {
+            ec_fsm_slave_exec(&slave->fsm);
+        }
         up(&master->master_sem);
 
         // queue and send
         down(&master->io_sem);
-        ec_master_queue_datagram(master, &master->fsm_datagram);
+        if (fsm_exec) {
+            ec_master_queue_datagram(master, &master->fsm_datagram);
+        }
+        ec_master_inject_sdo_datagrams(master);
         ecrt_master_send(master);
         up(&master->io_sem);
-        
-schedule:
+
         if (ec_fsm_master_idle(&master->fsm)) {
             set_current_state(TASK_INTERRUPTIBLE);
             schedule_timeout(1);
@@ -1045,35 +1088,38 @@
 
 /*****************************************************************************/
 
-/** Master kernel thread function for IDLE phase.
+/** Master kernel thread function for OPERATION phase.
  */
 static int ec_master_operation_thread(void *priv_data)
 {
     ec_master_t *master = (ec_master_t *) priv_data;
-
+    ec_slave_t *slave = NULL;
+    int fsm_exec;
     if (master->debug_level)
         EC_DBG("Operation thread running.\n");
 
     while (!kthread_should_stop()) {
         ec_datagram_output_stats(&master->fsm_datagram);
-        if (master->injection_seq_rt != master->injection_seq_fsm ||
-                master->fsm_datagram.state == EC_DATAGRAM_SENT ||
-                master->fsm_datagram.state == EC_DATAGRAM_QUEUED)
-            goto schedule;
-
-        // output statistics
-        ec_master_output_stats(master);
-
-        // execute master state machine
-        if (down_interruptible(&master->master_sem))
-            break;
-        ec_fsm_master_exec(&master->fsm);
-        up(&master->master_sem);
-
-        // inject datagram
-        master->injection_seq_fsm++;
-
-schedule:
+        if (master->injection_seq_rt == master->injection_seq_fsm) {
+            // output statistics
+            ec_master_output_stats(master);
+
+            fsm_exec = 0;
+            // execute master & slave state machines
+            if (down_interruptible(&master->master_sem))
+                break;
+            fsm_exec += ec_fsm_master_exec(&master->fsm);
+            for (slave = master->slaves;
+                    slave < master->slaves + master->slave_count;
+                    slave++) {
+                ec_fsm_slave_exec(&slave->fsm);
+            }
+            up(&master->master_sem);
+
+            // inject datagrams (let the rt thread queue them, see ecrt_master_send)
+            if (fsm_exec)
+                master->injection_seq_fsm++;
+        }
         if (ec_fsm_master_idle(&master->fsm)) {
             set_current_state(TASK_INTERRUPTIBLE);
             schedule_timeout(1);
@@ -1797,10 +1843,11 @@
     ec_datagram_t *datagram, *n;
 
     if (master->injection_seq_rt != master->injection_seq_fsm) {
-        // inject datagram produced by master FSM
+        // inject datagrams produced by master & slave FSMs
         ec_master_queue_datagram(master, &master->fsm_datagram);
         master->injection_seq_rt = master->injection_seq_fsm;
     }
+    ec_master_inject_sdo_datagrams(master);
 
     if (unlikely(!master->main_device.link_state)) {
         // link is down, no datagram can be sent