master/master.c
changeset 446 8fede404c01f
parent 444 31223539fc00
child 448 e4b76dc7910c
--- a/master/master.c	Wed Oct 25 16:53:17 2006 +0000
+++ b/master/master.c	Thu Oct 26 16:29:26 2006 +0000
@@ -59,6 +59,7 @@
 void ec_master_idle_run(void *);
 void ec_master_eoe_run(unsigned long);
 void ec_master_check_sdo(unsigned long);
+int ec_master_measure_bus_time(ec_master_t *);
 ssize_t ec_show_master_attribute(struct kobject *, struct attribute *, char *);
 ssize_t ec_store_master_attribute(struct kobject *, struct attribute *,
                                   const char *, size_t);
@@ -109,28 +110,55 @@
 
     EC_INFO("Initializing master %i.\n", index);
 
+    atomic_set(&master->available, 1);
     master->index = index;
+
     master->device = NULL;
     init_MUTEX(&master->device_sem);
-    atomic_set(&master->available, 1);
+
+    master->mode = EC_MASTER_MODE_ORPHANED;
+
     INIT_LIST_HEAD(&master->slaves);
+    master->slave_count = 0;
+
     INIT_LIST_HEAD(&master->datagram_queue);
+    master->datagram_index = 0;
+
     INIT_LIST_HEAD(&master->domains);
-    INIT_LIST_HEAD(&master->eoe_handlers);
+    master->debug_level = 0;
+
+    master->stats.timeouts = 0;
+    master->stats.corrupted = 0;
+    master->stats.skipped = 0;
+    master->stats.unmatched = 0;
+    master->stats.output_jiffies = 0;
+
     INIT_WORK(&master->idle_work, ec_master_idle_run, (void *) master);
+
+    for (i = 0; i < HZ; i++) {
+        master->idle_cycle_times[i] = 0;
+        master->eoe_cycle_times[i] = 0;
+    }
+    master->idle_cycle_time_pos = 0;
+    master->eoe_cycle_time_pos = 0;
+
     init_timer(&master->eoe_timer);
     master->eoe_timer.function = ec_master_eoe_run;
     master->eoe_timer.data = (unsigned long) master;
-    master->internal_lock = SPIN_LOCK_UNLOCKED;
     master->eoe_running = 0;
     master->eoe_checked = 0;
-    for (i = 0; i < HZ; i++) {
-        master->idle_cycle_times[i] = 0;
-        master->eoe_cycle_times[i] = 0;
-    }
-    master->idle_cycle_time_pos = 0;
-    master->eoe_cycle_time_pos = 0;
-    master->debug_level = 0;
+    INIT_LIST_HEAD(&master->eoe_handlers);
+
+    master->internal_lock = SPIN_LOCK_UNLOCKED;
+    master->request_cb = NULL;
+    master->release_cb = NULL;
+    master->cb_data = NULL;
+
+    master->eeprom_write_enable = 0;
+
+    master->sdo_request = NULL;
+    master->sdo_seq_user = 0;
+    master->sdo_seq_master = 0;
     init_MUTEX(&master->sdo_sem);
     init_timer(&master->sdo_timer);
     master->sdo_timer.function = ec_master_check_sdo;
@@ -175,7 +203,6 @@
         return -1;
     }
 
-    ec_master_reset(master);
     return 0;
 
  out_clear_eoe:
@@ -203,10 +230,17 @@
 {
     ec_master_t *master = container_of(kobj, ec_master_t, kobj);
     ec_eoe_t *eoe, *next_eoe;
-
-    EC_INFO("Clearing master %i...\n", master->index);
-
-    ec_master_reset(master);
+    ec_datagram_t *datagram, *next_c;
+
+    ec_master_clear_slaves(master);
+
+    // empty datagram queue
+    list_for_each_entry_safe(datagram, next_c,
+                             &master->datagram_queue, queue) {
+        datagram->state = EC_DATAGRAM_ERROR;
+        list_del_init(&datagram->queue);
+    }
+
     ec_fsm_clear(&master->fsm);
     destroy_workqueue(master->workqueue);
     ec_xmldev_clear(&master->xmldev);
@@ -218,11 +252,6 @@
         kfree(eoe);
     }
 
-    if (master->device) {
-        ec_device_clear(master->device);
-        kfree(master->device);
-    }
-
     EC_INFO("Master %i cleared.\n", master->index);
 
     kfree(master);
@@ -231,57 +260,6 @@
 /*****************************************************************************/
 
 /**
-   Resets the master.
-   Note: This function has to be called, everytime ec_master_release() is
-   called, to free the slave list, domains etc.
-*/
-
-void ec_master_reset(ec_master_t *master /**< EtherCAT master */)
-{
-    ec_datagram_t *datagram, *next_c;
-    ec_domain_t *domain, *next_d;
-
-    ec_master_eoe_stop(master);
-    ec_master_idle_stop(master);
-    ec_master_flush_sdo_requests(master);
-    ec_master_clear_slaves(master);
-
-    // empty datagram queue
-    list_for_each_entry_safe(datagram, next_c,
-                             &master->datagram_queue, queue) {
-        datagram->state = EC_DATAGRAM_ERROR;
-        list_del_init(&datagram->queue);
-    }
-
-    // clear domains
-    list_for_each_entry_safe(domain, next_d, &master->domains, list) {
-        list_del(&domain->list);
-        kobject_del(&domain->kobj);
-        kobject_put(&domain->kobj);
-    }
-
-    master->datagram_index = 0;
-
-    master->stats.timeouts = 0;
-    master->stats.corrupted = 0;
-    master->stats.skipped = 0;
-    master->stats.unmatched = 0;
-    master->stats.output_jiffies = 0;
-
-    master->mode = EC_MASTER_MODE_ORPHANED;
-
-    master->request_cb = NULL;
-    master->release_cb = NULL;
-    master->cb_data = NULL;
-
-    master->eeprom_write_enable = 0;
-
-    ec_fsm_reset(&master->fsm);
-}
-
-/*****************************************************************************/
-
-/**
    Clears all slaves.
 */
 
@@ -294,6 +272,7 @@
         kobject_del(&slave->kobj);
         kobject_put(&slave->kobj);
     }
+
     master->slave_count = 0;
 }
 
@@ -315,6 +294,123 @@
 /*****************************************************************************/
 
 /**
+*/
+
+int ec_master_enter_idle_mode(ec_master_t *master /**< EtherCAT master */)
+{
+    master->mode = EC_MASTER_MODE_IDLE;
+    queue_delayed_work(master->workqueue, &master->idle_work, 1);
+    return 0;
+}
+
+/*****************************************************************************/
+
+/**
+*/
+
+void ec_master_leave_idle_mode(ec_master_t *master /**< EtherCAT master */)
+{
+    ec_master_eoe_stop(master);
+
+    master->mode = EC_MASTER_MODE_ORPHANED;
+    if (!cancel_delayed_work(&master->idle_work)) {
+        flush_workqueue(master->workqueue);
+    }
+
+    ec_master_flush_sdo_requests(master);
+}
+
+/*****************************************************************************/
+
+/**
+*/
+
+int ec_master_enter_operation_mode(ec_master_t *master /**< EtherCAT master */)
+{
+    ec_slave_t *slave;
+    ec_datagram_t *datagram = &master->fsm.datagram;
+
+    master->mode = EC_MASTER_MODE_OPERATION;
+    if (!cancel_delayed_work(&master->idle_work)) {
+        flush_workqueue(master->workqueue);
+    }
+
+    // wait for FSM datagram
+    if (datagram->state == EC_DATAGRAM_SENT) {;
+        while (get_cycles() - datagram->cycles_sent
+               < (cycles_t) EC_IO_TIMEOUT /* us */ * (cpu_khz / 1000)) {}
+        ecrt_master_receive(master);
+    }
+
+    // finish running FSM
+    while (ec_fsm_exec(&master->fsm)) {
+        ec_master_sync_io(master);
+    }
+
+    if (!ec_fsm_success(&master->fsm)) {
+        EC_ERR("Master state machine failure!\n");
+        goto out_idle;
+    }
+
+    if (master->debug_level) {
+        if (ec_master_measure_bus_time(master)) {
+            EC_ERR("Bus time measuring failed!\n");
+            goto out_idle;
+        }
+    }
+
+    // set initial slave states
+    list_for_each_entry(slave, &master->slaves, list) {
+        if (ec_slave_is_coupler(slave)) {
+            ec_slave_request_state(slave, EC_SLAVE_STATE_OP);
+        }
+        else {
+            ec_slave_request_state(slave, EC_SLAVE_STATE_PREOP);
+        }
+    }
+
+    return 0;
+
+ out_idle:
+    master->mode = EC_MASTER_MODE_IDLE;
+    queue_delayed_work(master->workqueue, &master->idle_work, 1);
+    return -1;
+}
+
+/*****************************************************************************/
+
+/**
+*/
+
+void ec_master_leave_operation_mode(ec_master_t *master
+                                    /**< EtherCAT master */)
+{
+    ec_slave_t *slave;
+    ec_domain_t *domain, *next_d;
+
+    // clear domains
+    list_for_each_entry_safe(domain, next_d, &master->domains, list) {
+        ec_domain_dequeue_datagrams(domain);
+        list_del(&domain->list);
+        kobject_del(&domain->kobj);
+        kobject_put(&domain->kobj);
+    }
+
+    master->request_cb = NULL;
+    master->release_cb = NULL;
+    master->cb_data = NULL;
+
+    list_for_each_entry(slave, &master->slaves, list) {
+        ec_slave_reset(slave);
+    }
+
+    master->mode = EC_MASTER_MODE_IDLE;
+    queue_delayed_work(master->workqueue, &master->idle_work, 1);
+}
+
+/*****************************************************************************/
+
+/**
    Places a datagram in the datagram queue.
 */
 
@@ -545,32 +641,6 @@
 /*****************************************************************************/
 
 /**
-   Scans the EtherCAT bus for slaves.
-   Creates a list of slave structures for further processing.
-   \return 0 in case of success, else < 0
-*/
-
-int ec_master_bus_scan(ec_master_t *master /**< EtherCAT master */)
-{
-    ec_fsm_t *fsm = &master->fsm;
-
-    ec_fsm_startup(fsm); // init startup state machine
-
-    while (ec_fsm_exec(fsm)) {
-        ec_master_sync_io(master);
-    }
-
-    if (!ec_fsm_startup_success(fsm)) {
-        ec_master_clear_slaves(master);
-        return -1;
-    }
-
-    return 0;
-}
-
-/*****************************************************************************/
-
-/**
    Output statistics in cyclic mode.
    This function outputs statistical data on demand, but not more often than
    necessary. The output happens at most once a second.
@@ -607,52 +677,6 @@
 /*****************************************************************************/
 
 /**
-   Starts the Idle mode.
-*/
-
-void ec_master_idle_start(ec_master_t *master /**< EtherCAT master */)
-{
-    if (master->mode == EC_MASTER_MODE_IDLE) return;
-
-    if (master->mode == EC_MASTER_MODE_OPERATION) {
-        EC_ERR("ec_master_idle_start: Master already running!\n");
-        return;
-    }
-
-    EC_INFO("Starting Idle mode.\n");
-
-    master->mode = EC_MASTER_MODE_IDLE;
-    ec_fsm_reset(&master->fsm);
-    queue_delayed_work(master->workqueue, &master->idle_work, 1);
-}
-
-/*****************************************************************************/
-
-/**
-   Stops the Idle mode.
-*/
-
-void ec_master_idle_stop(ec_master_t *master /**< EtherCAT master */)
-{
-    if (master->mode != EC_MASTER_MODE_IDLE) return;
-
-    ec_master_eoe_stop(master);
-
-    EC_INFO("Stopping Idle mode.\n");
-    master->mode = EC_MASTER_MODE_ORPHANED; // this is important for the
-                                            // IDLE work function to not
-                                            // queue itself again
-
-    if (!cancel_delayed_work(&master->idle_work)) {
-        flush_workqueue(master->workqueue);
-    }
-
-    ec_master_clear_slaves(master);
-}
-
-/*****************************************************************************/
-
-/**
    Idle mode function.
 */
 
@@ -947,16 +971,16 @@
             coupled++;
             EC_INFO("Coupling device %s to slave %i.\n",
                     eoe->dev->name, slave->ring_position);
-            if (eoe->opened) slave->requested_state = EC_SLAVE_STATE_OP;
-            else slave->requested_state = EC_SLAVE_STATE_INIT;
-            slave->error_flag = 0;
+            if (eoe->opened)
+                ec_slave_request_state(slave, EC_SLAVE_STATE_OP);
+            else
+                ec_slave_request_state(slave, EC_SLAVE_STATE_PREOP);
             break;
         }
 
         if (!found) {
             EC_WARN("No EoE handler for slave %i!\n", slave->ring_position);
-            slave->requested_state = EC_SLAVE_STATE_INIT;
-            slave->error_flag = 0;
+            ec_slave_request_state(slave, EC_SLAVE_STATE_INIT);
         }
     }
 
@@ -995,8 +1019,7 @@
     // decouple all EoE handlers
     list_for_each_entry(eoe, &master->eoe_handlers, list) {
         if (eoe->slave) {
-            eoe->slave->requested_state = EC_SLAVE_STATE_INIT;
-            eoe->slave->error_flag = 0;
+            ec_slave_request_state(eoe->slave, EC_SLAVE_STATE_PREOP);
             eoe->slave = NULL;
         }
     }
@@ -1253,27 +1276,23 @@
         domain_offset += domain->data_size;
     }
 
-    // determine initial states.
-    list_for_each_entry(slave, &master->slaves, list) {
-        if (ec_slave_is_coupler(slave) || slave->registered) {
-            slave->requested_state = EC_SLAVE_STATE_OP;
-        }
-        else {
-            slave->requested_state = EC_SLAVE_STATE_PREOP;
-        }
-    }
-
-    ec_fsm_configuration(fsm); // init configuration state machine
-
+    // execute master FSM until termination
     while (ec_fsm_exec(fsm)) {
         ec_master_sync_io(master);
     }
 
-    if (!ec_fsm_configuration_success(fsm)) {
+    if (!ec_fsm_success(fsm)) {
+        EC_ERR("Error in master state machine.\n");
         return -1;
     }
 
-    ec_fsm_reset(&master->fsm); // prepare for operation state machine
+    // check, if all slaves have been configured
+    list_for_each_entry(slave, &master->slaves, list) {
+        if (slave->error_flag || !slave->online) {
+            EC_ERR("Failed to configure slave %i!\n", slave->ring_position);
+            return -1;
+        }
+    }
 
     return 0;
 }
@@ -1289,13 +1308,21 @@
 {
     ec_fsm_t *fsm = &master->fsm;
     ec_slave_t *slave;
-
+    ec_datagram_t *datagram = &master->fsm.datagram;
+
+    // wait for FSM datagram
+    if (datagram->state == EC_DATAGRAM_SENT) {
+        while (get_cycles() - datagram->cycles_sent
+               < (cycles_t) EC_IO_TIMEOUT /* us */ * (cpu_khz / 1000)) {}
+        ecrt_master_receive(master);
+    }
+
+    // set states for all slaves
     list_for_each_entry(slave, &master->slaves, list) {
-        slave->requested_state = EC_SLAVE_STATE_INIT;
-    }
-
-    ec_fsm_configuration(fsm); // init configuration state machine
-
+        ec_slave_request_state(slave, EC_SLAVE_STATE_PREOP);
+    }
+
+    // execute master FSM to deactivate slaves
     while (ec_fsm_exec(fsm)) {
         ec_master_sync_io(master);
     }
@@ -1416,7 +1443,7 @@
 
     // queue datagrams of all domains
     list_for_each_entry(domain, &master->domains, list)
-        ec_domain_queue(domain);
+        ec_domain_queue_datagrams(domain);
 
     ecrt_master_send(master);
 
@@ -1443,7 +1470,7 @@
     // output statistics
     ec_master_output_stats(master);
 
-    // execute master state machine
+    // execute master state machine in a loop
     ec_fsm_exec(&master->fsm);
 }