diff -r 60b2aad9d40b -r 1cc865ba17c2 master/master.c --- 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); } /*****************************************************************************/