--- a/master/master.c Fri Oct 13 10:07:10 2006 +0000
+++ b/master/master.c Tue Nov 07 12:13:30 2006 +0000
@@ -54,9 +54,13 @@
/*****************************************************************************/
+void ec_master_clear(struct kobject *);
+void ec_master_destroy_domains(ec_master_t *);
void ec_master_sync_io(ec_master_t *);
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);
@@ -106,27 +110,60 @@
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;
+ 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;
+ master->sdo_timer.data = (unsigned long) master;
+ init_completion(&master->sdo_complete);
// create workqueue
if (!(master->workqueue = create_singlethread_workqueue("EtherCAT"))) {
@@ -159,8 +196,12 @@
kobject_put(&master->kobj);
return -1;
}
-
- ec_master_reset(master);
+ if (kobject_add(&master->kobj)) {
+ EC_ERR("Failed to add master kobj.\n");
+ kobject_put(&master->kobj);
+ return -1;
+ }
+
return 0;
out_clear_eoe:
@@ -178,18 +219,40 @@
/**
Master destructor.
- Removes all pending datagrams, clears the slave list, clears all domains
- and frees the device.
+ Clears the kobj-hierarchy bottom up and frees the master.
+*/
+
+void ec_master_destroy(ec_master_t *master /**< EtherCAT master */)
+{
+ ec_master_destroy_slaves(master);
+ ec_master_destroy_domains(master);
+
+ // destroy self
+ kobject_del(&master->kobj);
+ kobject_put(&master->kobj); // free master
+}
+
+/*****************************************************************************/
+
+/**
+ Clear and free master.
+ This method is called by the kobject,
+ once there are no more references to it.
*/
void ec_master_clear(struct kobject *kobj /**< kobject of the master */)
{
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_datagram;
+
+ // dequeue all datagrams
+ list_for_each_entry_safe(datagram, next_datagram,
+ &master->datagram_queue, queue) {
+ datagram->state = EC_DATAGRAM_ERROR;
+ list_del_init(&datagram->queue);
+ }
+
ec_fsm_clear(&master->fsm);
destroy_workqueue(master->workqueue);
@@ -200,81 +263,193 @@
kfree(eoe);
}
- if (master->device) {
- ec_device_clear(master->device);
- kfree(master->device);
- }
-
- EC_INFO("Master %i cleared.\n", master->index);
-}
-
-/*****************************************************************************/
-
-/**
- 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_INFO("Master %i freed.\n", master->index);
+
+ kfree(master);
+}
+
+/*****************************************************************************/
+
+/**
+ Destroy all slaves.
+*/
+
+void ec_master_destroy_slaves(ec_master_t *master)
+{
+ ec_slave_t *slave, *next_slave;
+
+ list_for_each_entry_safe(slave, next_slave, &master->slaves, list) {
+ list_del(&slave->list);
+ ec_slave_destroy(slave);
+ }
+
+ master->slave_count = 0;
+}
+
+/*****************************************************************************/
+
+/**
+ Destroy all domains.
+*/
+
+void ec_master_destroy_domains(ec_master_t *master)
+{
ec_domain_t *domain, *next_d;
- ec_master_eoe_stop(master);
- ec_master_idle_stop(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->debug_level = 0;
-
- master->stats.timeouts = 0;
- master->stats.corrupted = 0;
- master->stats.skipped = 0;
- master->stats.unmatched = 0;
- master->stats.output_jiffies = 0;
+ ec_domain_destroy(domain);
+ }
+}
+
+/*****************************************************************************/
+
+/**
+ Flushes the SDO request queue.
+*/
+
+void ec_master_flush_sdo_requests(ec_master_t *master)
+{
+ del_timer_sync(&master->sdo_timer);
+ complete(&master->sdo_complete);
+ master->sdo_request = NULL;
+ master->sdo_seq_user = 0;
+ master->sdo_seq_master = 0;
+}
+
+/*****************************************************************************/
+
+/**
+*/
+
+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;
+ while (!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;
+ while (!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 master FSM
+ if (ec_fsm_running(&master->fsm)) {
+ while (ec_fsm_exec(&master->fsm)) {
+ ec_master_sync_io(master);
+ }
+ }
+
+ 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_fsm_t *fsm = &master->fsm;
+ 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);
+ }
+
+ // finish running master FSM
+ if (ec_fsm_running(fsm)) {
+ while (ec_fsm_exec(fsm)) {
+ ec_master_sync_io(master);
+ }
+ }
+
+ // set states for all slaves
+ list_for_each_entry(slave, &master->slaves, list) {
+ ec_slave_reset(slave);
+ ec_slave_request_state(slave, EC_SLAVE_STATE_PREOP);
+
+ fsm->slave = slave;
+ fsm->slave_state = ec_fsm_slaveconf_state_start;
+
+ do {
+ fsm->slave_state(fsm);
+ ec_master_sync_io(master);
+ }
+ while (fsm->slave_state != ec_fsm_slave_state_end
+ && fsm->slave_state != ec_fsm_slave_state_error);
+ }
+
+ ec_master_destroy_domains(master);
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.
-*/
-
-void ec_master_clear_slaves(ec_master_t *master)
-{
- ec_slave_t *slave, *next_slave;
-
- list_for_each_entry_safe(slave, next_slave, &master->slaves, list) {
- list_del(&slave->list);
- kobject_del(&slave->kobj);
- kobject_put(&slave->kobj);
- }
- master->slave_count = 0;
+ master->mode = EC_MASTER_MODE_IDLE;
+ queue_delayed_work(master->workqueue, &master->idle_work, 1);
}
/*****************************************************************************/
@@ -301,6 +476,7 @@
list_add_tail(&datagram->queue, &master->datagram_queue);
datagram->state = EC_DATAGRAM_QUEUED;
+ datagram->cycles_queued = get_cycles();
}
/*****************************************************************************/
@@ -312,15 +488,18 @@
void ec_master_send_datagrams(ec_master_t *master /**< EtherCAT master */)
{
- ec_datagram_t *datagram;
+ ec_datagram_t *datagram, *next;
size_t datagram_size;
uint8_t *frame_data, *cur_data;
void *follows_word;
- cycles_t cycles_start, cycles_end;
+ cycles_t cycles_start, cycles_sent, cycles_end;
+ unsigned long jiffies_sent;
unsigned int frame_count, more_datagrams_waiting;
-
+ struct list_head sent_datagrams;
+
+ cycles_start = get_cycles();
frame_count = 0;
- cycles_start = get_cycles();
+ INIT_LIST_HEAD(&sent_datagrams);
if (unlikely(master->debug_level > 1))
EC_DBG("ec_master_send_datagrams\n");
@@ -344,8 +523,7 @@
break;
}
- datagram->state = EC_DATAGRAM_SENT;
- datagram->cycles_sent = cycles_start;
+ list_add_tail(&datagram->sent, &sent_datagrams);
datagram->index = master->datagram_index++;
if (unlikely(master->debug_level > 1))
@@ -373,7 +551,7 @@
cur_data += EC_DATAGRAM_FOOTER_SIZE;
}
- if (cur_data - frame_data == EC_FRAME_HEADER_SIZE) {
+ if (list_empty(&sent_datagrams)) {
if (unlikely(master->debug_level > 1))
EC_DBG("nothing to send.\n");
break;
@@ -392,6 +570,17 @@
// send frame
ec_device_send(master->device, cur_data - frame_data);
+ cycles_sent = get_cycles();
+ jiffies_sent = jiffies;
+
+ // set datagram states and sending timestamps
+ list_for_each_entry_safe(datagram, next, &sent_datagrams, sent) {
+ datagram->state = EC_DATAGRAM_SENT;
+ datagram->cycles_sent = cycles_sent;
+ datagram->jiffies_sent = jiffies_sent;
+ list_del_init(&datagram->sent); // empty list of sent datagrams
+ }
+
frame_count++;
}
while (more_datagrams_waiting);
@@ -487,6 +676,8 @@
// dequeue the received datagram
datagram->state = EC_DATAGRAM_RECEIVED;
+ datagram->cycles_received = master->device->cycles_isr;
+ datagram->jiffies_received = master->device->jiffies_isr;
list_del_init(&datagram->queue);
}
}
@@ -494,34 +685,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
-
- do {
- ec_fsm_execute(fsm);
- ec_master_sync_io(master);
- }
- while (ec_fsm_startup_running(fsm));
-
- 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.
@@ -533,19 +696,23 @@
master->stats.output_jiffies = jiffies;
if (master->stats.timeouts) {
- EC_WARN("%i datagrams TIMED OUT!\n", master->stats.timeouts);
+ EC_WARN("%i datagram%s TIMED OUT!\n", master->stats.timeouts,
+ master->stats.timeouts == 1 ? "" : "s");
master->stats.timeouts = 0;
}
if (master->stats.corrupted) {
- EC_WARN("%i frame(s) CORRUPTED!\n", master->stats.corrupted);
+ EC_WARN("%i frame%s CORRUPTED!\n", master->stats.corrupted,
+ master->stats.corrupted == 1 ? "" : "s");
master->stats.corrupted = 0;
}
if (master->stats.skipped) {
- EC_WARN("%i datagram(s) SKIPPED!\n", master->stats.skipped);
+ EC_WARN("%i datagram%s SKIPPED!\n", master->stats.skipped,
+ master->stats.skipped == 1 ? "" : "s");
master->stats.skipped = 0;
}
if (master->stats.unmatched) {
- EC_WARN("%i datagram(s) UNMATCHED!\n", master->stats.unmatched);
+ EC_WARN("%i datagram%s UNMATCHED!\n", master->stats.unmatched,
+ master->stats.unmatched == 1 ? "" : "s");
master->stats.unmatched = 0;
}
}
@@ -554,52 +721,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.
*/
@@ -615,7 +736,7 @@
ecrt_master_receive(master);
// execute master state machine
- ec_fsm_execute(&master->fsm);
+ ec_fsm_exec(&master->fsm);
ecrt_master_send(master);
cycles_end = get_cycles();
@@ -649,11 +770,9 @@
sync_size = ec_slave_calc_sync_size(slave, sync);
if (slave->master->debug_level) {
- EC_INFO("Slave %i, sync manager %i:\n", slave->ring_position,
- sync->index);
- EC_INFO(" Address: 0x%04X\n", sync->physical_start_address);
- EC_INFO(" Size: %i\n", sync_size);
- EC_INFO(" Control: 0x%02X\n", sync->control_register);
+ EC_DBG("Slave %3i, SM %i: Addr 0x%04X, Size %3i, Ctrl 0x%02X, En %i\n",
+ slave->ring_position, sync->index, sync->physical_start_address,
+ sync_size, sync->control_register, sync->enable);
}
EC_WRITE_U16(data, sync->physical_start_address);
@@ -679,6 +798,14 @@
sync_size = ec_slave_calc_sync_size(slave, fmmu->sync);
+ if (slave->master->debug_level) {
+ EC_DBG("Slave %3i, FMMU %2i:"
+ " LogAddr 0x%08X, Size %3i, PhysAddr 0x%04X, Dir %s\n",
+ slave->ring_position, fmmu->index, fmmu->logical_start_address,
+ sync_size, fmmu->sync->physical_start_address,
+ ((fmmu->sync->control_register & 0x04) ? "out" : "in"));
+ }
+
EC_WRITE_U32(data, fmmu->logical_start_address);
EC_WRITE_U16(data + 4, sync_size); // size of fmmu
EC_WRITE_U8 (data + 6, 0x00); // logical start bit
@@ -706,7 +833,7 @@
ec_eoe_t *eoe;
uint32_t cur, sum, min, max, pos, i;
- off += sprintf(buffer + off, "\nVersion: " EC_MASTER_VERSION);
+ off += sprintf(buffer + off, "\nVersion: %s", ec_master_version_str);
off += sprintf(buffer + off, "\nMode: ");
switch (master->mode) {
case EC_MASTER_MODE_ORPHANED:
@@ -888,16 +1015,18 @@
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;
+ if (master->debug_level)
+ EC_WARN("No EoE handler for slave %i!\n",
+ slave->ring_position);
+ ec_slave_request_state(slave, EC_SLAVE_STATE_PREOP);
}
}
@@ -936,8 +1065,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;
}
}
@@ -946,6 +1074,7 @@
}
/*****************************************************************************/
+
/**
Does the Ethernet-over-EtherCAT processing.
*/
@@ -1009,6 +1138,25 @@
/*****************************************************************************/
/**
+*/
+
+void ec_master_check_sdo(unsigned long data /**< master pointer */)
+{
+ ec_master_t *master = (ec_master_t *) data;
+
+ if (master->sdo_seq_master != master->sdo_seq_user) {
+ master->sdo_timer.expires = jiffies + 10;
+ add_timer(&master->sdo_timer);
+ return;
+ }
+
+ // master has processed the request
+ complete(&master->sdo_complete);
+}
+
+/*****************************************************************************/
+
+/**
Calculates Advanced Position Adresses.
*/
@@ -1048,8 +1196,7 @@
int ec_master_measure_bus_time(ec_master_t *master)
{
ec_datagram_t datagram;
- cycles_t cycles_start, cycles_end, cycles_timeout;
- uint32_t times[100], sum, min, max, i;
+ uint32_t cur, sum, min, max, i;
ec_datagram_init(&datagram);
@@ -1059,7 +1206,7 @@
return -1;
}
- cycles_timeout = (cycles_t) EC_IO_TIMEOUT * (cpu_khz / 1000);
+ ecrt_master_receive(master);
sum = 0;
min = 0xFFFFFFFF;
@@ -1068,11 +1215,9 @@
for (i = 0; i < 100; i++) {
ec_master_queue_datagram(master, &datagram);
ecrt_master_send(master);
- cycles_start = get_cycles();
-
- while (1) { // active waiting
- ec_device_call_isr(master->device);
- cycles_end = get_cycles(); // take current time
+
+ while (1) {
+ ecrt_master_receive(master);
if (datagram.state == EC_DATAGRAM_RECEIVED) {
break;
@@ -1081,25 +1226,25 @@
EC_WARN("Failed to measure bus time.\n");
goto error;
}
- else if (cycles_end - cycles_start >= cycles_timeout) {
+ else if (datagram.state == EC_DATAGRAM_TIMED_OUT) {
EC_WARN("Timeout while measuring bus time.\n");
goto error;
}
}
- times[i] = (unsigned int) (cycles_end - cycles_start) * 1000 / cpu_khz;
- sum += times[i];
- if (times[i] > max) max = times[i];
- if (times[i] < min) min = times[i];
- }
-
- EC_INFO("Bus time is (min/avg/max) %u/%u.%u/%u us.\n",
- min, sum / 100, sum % 100, max);
+ cur = (unsigned int) (datagram.cycles_received
+ - datagram.cycles_sent) * 1000 / cpu_khz;
+ sum += cur;
+ if (cur > max) max = cur;
+ if (cur < min) min = cur;
+ }
+
+ EC_DBG("Bus time is (min/avg/max) %u / %u.%u / %u us.\n",
+ min, sum / 100, sum % 100, max);
+ ec_datagram_clear(&datagram);
return 0;
error:
- // Dequeue and free datagram
- list_del(&datagram.queue);
ec_datagram_clear(&datagram);
return -1;
}
@@ -1121,7 +1266,7 @@
if (!(domain = (ec_domain_t *) kmalloc(sizeof(ec_domain_t), GFP_KERNEL))) {
EC_ERR("Error allocating domain memory!\n");
- goto out_return;
+ return NULL;
}
if (list_empty(&master->domains)) index = 0;
@@ -1132,21 +1277,12 @@
if (ec_domain_init(domain, master, index)) {
EC_ERR("Failed to init domain.\n");
- goto out_return;
- }
-
- if (kobject_add(&domain->kobj)) {
- EC_ERR("Failed to add domain kobject.\n");
- goto out_put;
+ return NULL;
}
list_add_tail(&domain->list, &master->domains);
+
return domain;
-
- out_put:
- kobject_put(&domain->kobj);
- out_return:
- return NULL;
}
/*****************************************************************************/
@@ -1177,29 +1313,23 @@
domain_offset += domain->data_size;
}
- // determine initial states.
+ // configure all slaves
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
-
- do {
- ec_fsm_execute(fsm);
- ec_master_sync_io(master);
- }
- while (ec_fsm_configuration_running(fsm));
-
- if (!ec_fsm_configuration_success(fsm)) {
- return -1;
- }
-
- ec_fsm_reset(&master->fsm); // prepare for operation state machine
+ fsm->slave = slave;
+ fsm->slave_state = ec_fsm_slaveconf_state_start;
+
+ do {
+ fsm->slave_state(fsm);
+ ec_master_sync_io(master);
+ }
+ while (fsm->slave_state != ec_fsm_slave_state_end
+ && fsm->slave_state != ec_fsm_slave_state_error);
+
+ if (fsm->slave_state == ec_fsm_slave_state_error) {
+ EC_ERR("Failed to configure slave %i!\n", slave->ring_position);
+ return -1;
+ }
+ }
return 0;
}
@@ -1208,25 +1338,14 @@
/**
Resets all slaves to INIT state.
+ This method is deprecated and will disappear in the next version
+ of the realtime interface. The functionality is moved to
+ ecrt_master_release().
\ingroup RealtimeInterface
*/
void ecrt_master_deactivate(ec_master_t *master /**< EtherCAT master */)
{
- ec_fsm_t *fsm = &master->fsm;
- ec_slave_t *slave;
-
- list_for_each_entry(slave, &master->slaves, list) {
- slave->requested_state = EC_SLAVE_STATE_INIT;
- }
-
- ec_fsm_configuration(fsm); // init configuration state machine
-
- do {
- ec_fsm_execute(fsm);
- ec_master_sync_io(master);
- }
- while (ec_fsm_configuration_running(fsm));
}
/*****************************************************************************/
@@ -1294,19 +1413,28 @@
void ecrt_master_receive(ec_master_t *master /**< EtherCAT master */)
{
ec_datagram_t *datagram, *next;
- cycles_t cycles_received, cycles_timeout;
-
+ cycles_t cycles_timeout;
+
+ // receive datagrams
ec_device_call_isr(master->device);
- cycles_received = get_cycles();
- cycles_timeout = EC_IO_TIMEOUT * cpu_khz / 1000;
+ 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) {
switch (datagram->state) {
+ case EC_DATAGRAM_QUEUED:
+ if (master->device->cycles_isr
+ - datagram->cycles_queued > cycles_timeout) {
+ list_del_init(&datagram->queue);
+ datagram->state = EC_DATAGRAM_TIMED_OUT;
+ master->stats.timeouts++;
+ ec_master_output_stats(master);
+ }
+ break;
case EC_DATAGRAM_SENT:
- case EC_DATAGRAM_QUEUED:
- if (cycles_received - datagram->cycles_sent > cycles_timeout) {
+ if (master->device->cycles_isr
+ - datagram->cycles_sent > cycles_timeout) {
list_del_init(&datagram->queue);
datagram->state = EC_DATAGRAM_TIMED_OUT;
master->stats.timeouts++;
@@ -1335,15 +1463,16 @@
// 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);
- cycles_start = get_cycles(); // take sending time
- cycles_timeout = (cycles_t) EC_IO_TIMEOUT * (cpu_khz / 1000);
+ cycles_start = get_cycles();
+ cycles_timeout = (cycles_t) EC_IO_TIMEOUT /* us */ * (cpu_khz / 1000);
// active waiting
while (1) {
+ udelay(100);
cycles_end = get_cycles();
if (cycles_end - cycles_start >= cycles_timeout) break;
}
@@ -1361,8 +1490,8 @@
// output statistics
ec_master_output_stats(master);
- // execute master state machine
- ec_fsm_execute(&master->fsm);
+ // execute master state machine in a loop
+ ec_fsm_exec(&master->fsm);
}
/*****************************************************************************/