Persistent slave lists.

This commit is contained in:
Florian Pose 2006-10-26 16:29:26 +00:00
parent 66f345ae29
commit b6e88ad403
13 changed files with 403 additions and 572 deletions

View File

@ -56,13 +56,16 @@ ec_domain_t *domain1 = NULL;
spinlock_t master_lock = SPIN_LOCK_UNLOCKED;
// data fields
#if 0
void *r_inputs;
void *r_outputs;
#endif
#if 0
void *r_ana_in;
#if 1
ec_pdo_reg_t domain1_pdos[] = {
{"2", Beckhoff_EL4132_Output1, &r_ana_out},
{"3", Beckhoff_EL5001_Value, NULL},
{"2", Beckhoff_EL3102_Input1, &r_ana_in},
{}
};
#endif
@ -82,8 +85,7 @@ void run(unsigned long data)
// process data
//k_pos = EC_READ_U32(r_ssi);
EC_WRITE_U8(r_outputs + 2, einaus ? 0xFF : 0x00);
//EC_WRITE_U8(r_outputs + 2, einaus ? 0xFF : 0x00);
// send
ecrt_master_run(master);
@ -142,12 +144,14 @@ int __init init_mini_module(void)
}
printk(KERN_INFO "Registering PDOs...\n");
#if 0
#if 1
if (ecrt_domain_register_pdo_list(domain1, domain1_pdos)) {
printk(KERN_ERR "PDO registration failed!\n");
goto out_release_master;
}
#endif
#if 0
if (!ecrt_domain_register_pdo_range(domain1, "0", Beckhoff_BK1120,
EC_DIR_OUTPUT, 0, 4, &r_outputs)) {
printk(KERN_ERR "PDO registration failed!\n");
@ -158,6 +162,7 @@ int __init init_mini_module(void)
printk(KERN_ERR "PDO registration failed!\n");
goto out_release_master;
}
#endif
#if 0
if (!(slave = ecrt_master_get_slave(master, "3")))

View File

@ -69,6 +69,7 @@
void ec_datagram_init(ec_datagram_t *datagram /**< EtherCAT datagram */)
{
INIT_LIST_HEAD(&datagram->queue); // mark as unqueued
datagram->type = EC_DATAGRAM_NONE;
datagram->address.logical = 0x00000000;
datagram->data = NULL;

View File

@ -139,8 +139,6 @@ void ec_domain_clear(struct kobject *kobj /**< kobject of the domain */)
domain = container_of(kobj, ec_domain_t, kobj);
EC_INFO("Clearing domain %i.\n", domain->index);
list_for_each_entry_safe(datagram, next, &domain->datagrams, list) {
ec_datagram_clear(datagram);
kfree(datagram);
@ -222,6 +220,9 @@ int ec_domain_reg_pdo_entry(ec_domain_t *domain, /**< EtherCAT domain */
data_reg->data_ptr = data_ptr;
list_add_tail(&data_reg->list, &domain->data_regs);
ec_slave_request_state(slave, EC_SLAVE_STATE_OP);
return 0;
}
@ -297,6 +298,9 @@ int ec_domain_reg_pdo_range(ec_domain_t *domain, /**< EtherCAT domain */
}
list_add_tail(&data_reg->list, &domain->data_regs);
ec_slave_request_state(slave, EC_SLAVE_STATE_OP);
return 0;
}
@ -448,7 +452,7 @@ int ec_domain_alloc(ec_domain_t *domain, /**< EtherCAT domain */
Places all process data datagrams in the masters datagram queue.
*/
void ec_domain_queue(ec_domain_t *domain /**< EtherCAT domain */)
void ec_domain_queue_datagrams(ec_domain_t *domain /**< EtherCAT domain */)
{
ec_datagram_t *datagram;
@ -459,6 +463,22 @@ void ec_domain_queue(ec_domain_t *domain /**< EtherCAT domain */)
/*****************************************************************************/
/**
Dequeues all datagrams from the masters datagram queue.
*/
void ec_domain_dequeue_datagrams(ec_domain_t *domain /**< EtherCAT domain */)
{
ec_datagram_t *datagram;
list_for_each_entry(datagram, &domain->datagrams, list) {
if (!list_empty(&datagram->queue)) // datagram queued?
list_del_init(&datagram->queue);
}
}
/*****************************************************************************/
/**
Formats attribute data for SysFS reading.
\return number of bytes to read
@ -518,18 +538,15 @@ ec_slave_t *ecrt_domain_register_pdo(ec_domain_t *domain,
if (!(slave = ecrt_master_get_slave(master, address))) return NULL;
if (ec_slave_validate(slave, vendor_id, product_code)) return NULL;
if (!data_ptr) {
// data_ptr is NULL => mark slave as "registered" (do not warn)
slave->registered = 1;
}
if (!data_ptr) return slave;
list_for_each_entry(pdo, &slave->sii_pdos, list) {
list_for_each_entry(entry, &pdo->entries, list) {
if (entry->index != pdo_index
|| entry->subindex != pdo_subindex) continue;
if (data_ptr) {
ec_domain_reg_pdo_entry(domain, slave, pdo, entry, data_ptr);
if (ec_domain_reg_pdo_entry(domain, slave, pdo, entry, data_ptr)) {
return NULL;
}
return slave;
@ -538,7 +555,6 @@ ec_slave_t *ecrt_domain_register_pdo(ec_domain_t *domain,
EC_ERR("Slave %i does not provide PDO 0x%04X:%i.\n",
slave->ring_position, pdo_index, pdo_subindex);
slave->registered = 0;
return NULL;
}
@ -609,11 +625,7 @@ ec_slave_t *ecrt_domain_register_pdo_range(ec_domain_t *domain,
if (!(slave = ecrt_master_get_slave(master, address))) return NULL;
if (ec_slave_validate(slave, vendor_id, product_code)) return NULL;
if (!data_ptr) {
// data_ptr is NULL => mark slave as "registered" (do not warn)
slave->registered = 1;
return slave;
}
if (!data_ptr) return slave;
if (ec_domain_reg_pdo_range(domain, slave,
direction, offset, length, data_ptr)) {
@ -666,7 +678,7 @@ void ecrt_domain_process(ec_domain_t *domain /**< EtherCAT domain */)
domain->working_counter_changes = 0;
}
ec_domain_queue(domain);
ec_domain_queue_datagrams(domain);
}
/*****************************************************************************/

View File

@ -76,8 +76,11 @@ struct ec_domain
/*****************************************************************************/
int ec_domain_init(ec_domain_t *, ec_master_t *, unsigned int);
int ec_domain_alloc(ec_domain_t *, uint32_t);
void ec_domain_queue(ec_domain_t *);
void ec_domain_queue_datagrams(ec_domain_t *);
void ec_domain_dequeue_datagrams(ec_domain_t *);
/*****************************************************************************/

View File

@ -629,8 +629,7 @@ int ec_eoedev_open(struct net_device *dev /**< EoE net_device */)
if (!eoe->slave)
EC_WARN("device %s is not coupled to any EoE slave!\n", dev->name);
else {
eoe->slave->requested_state = EC_SLAVE_STATE_OP;
eoe->slave->error_flag = 0;
ec_slave_request_state(eoe->slave, EC_SLAVE_STATE_OP);
}
return 0;
}
@ -652,8 +651,7 @@ int ec_eoedev_stop(struct net_device *dev /**< EoE net_device */)
if (!eoe->slave)
EC_WARN("device %s is not coupled to any EoE slave!\n", dev->name);
else {
eoe->slave->requested_state = EC_SLAVE_STATE_INIT;
eoe->slave->error_flag = 0;
ec_slave_request_state(eoe->slave, EC_SLAVE_STATE_PREOP);
}
return 0;
}

View File

@ -56,13 +56,8 @@ void ec_fsm_master_scan_slaves(ec_fsm_t *);
void ec_fsm_master_write_eeprom(ec_fsm_t *);
void ec_fsm_master_sdodict(ec_fsm_t *);
void ec_fsm_master_sdo_request(ec_fsm_t *);
void ec_fsm_startup_start(ec_fsm_t *);
void ec_fsm_startup_broadcast(ec_fsm_t *);
void ec_fsm_startup_scan(ec_fsm_t *);
void ec_fsm_configuration_start(ec_fsm_t *);
void ec_fsm_configuration_conf(ec_fsm_t *);
void ec_fsm_master_end(ec_fsm_t *);
void ec_fsm_master_error(ec_fsm_t *);
void ec_fsm_slavescan_start(ec_fsm_t *);
void ec_fsm_slavescan_address(ec_fsm_t *);
@ -80,8 +75,8 @@ void ec_fsm_slaveconf_sdoconf(ec_fsm_t *);
void ec_fsm_slaveconf_saveop(ec_fsm_t *);
void ec_fsm_slaveconf_op(ec_fsm_t *);
void ec_fsm_end(ec_fsm_t *);
void ec_fsm_error(ec_fsm_t *);
void ec_fsm_slave_end(ec_fsm_t *);
void ec_fsm_slave_error(ec_fsm_t *);
/*****************************************************************************/
@ -131,19 +126,6 @@ void ec_fsm_clear(ec_fsm_t *fsm /**< finite state machine */)
/*****************************************************************************/
/**
Resets the state machine.
*/
void ec_fsm_reset(ec_fsm_t *fsm /**< finite state machine */)
{
fsm->master_state = ec_fsm_master_start;
fsm->master_slaves_responding = 0;
fsm->master_slave_states = EC_SLAVE_STATE_UNKNOWN;
}
/*****************************************************************************/
/**
Executes the current state of the state machine.
\return false, if state machine has terminated
@ -153,232 +135,23 @@ int ec_fsm_exec(ec_fsm_t *fsm /**< finite state machine */)
{
fsm->master_state(fsm);
return fsm->master_state != ec_fsm_end &&
fsm->master_state != ec_fsm_error;
return fsm->master_state != ec_fsm_master_end
&& fsm->master_state != ec_fsm_master_error;
}
/*****************************************************************************/
/**
Initializes the master startup state machine.
\return true, if the master state machine terminated gracefully
*/
void ec_fsm_startup(ec_fsm_t *fsm)
int ec_fsm_success(ec_fsm_t *fsm /**< finite state machine */)
{
fsm->master_state = ec_fsm_startup_start;
}
/*****************************************************************************/
/**
Returns, if the master startup state machine terminated with success.
\return non-zero if successful.
*/
int ec_fsm_startup_success(ec_fsm_t *fsm /**< Finite state machine */)
{
return fsm->master_state == ec_fsm_end;
}
/*****************************************************************************/
/**
Initializes the master configuration state machine.
*/
void ec_fsm_configuration(ec_fsm_t *fsm)
{
fsm->master_state = ec_fsm_configuration_start;
}
/*****************************************************************************/
/**
Returns, if the master confuguration state machine terminated with success.
\return non-zero if successful.
*/
int ec_fsm_configuration_success(ec_fsm_t *fsm /**< Finite state machine */)
{
return fsm->master_state == ec_fsm_end;
return fsm->master_state == ec_fsm_master_end;
}
/******************************************************************************
* master startup state machine
*****************************************************************************/
/**
Master state: START.
Starts with getting slave count and slave states.
*/
void ec_fsm_startup_start(ec_fsm_t *fsm)
{
ec_datagram_brd(&fsm->datagram, 0x0130, 2);
ec_master_queue_datagram(fsm->master, &fsm->datagram);
fsm->master_state = ec_fsm_startup_broadcast;
}
/*****************************************************************************/
/**
Master state: BROADCAST.
Processes the broadcast read slave count and slaves states.
*/
void ec_fsm_startup_broadcast(ec_fsm_t *fsm /**< finite state machine */)
{
ec_datagram_t *datagram = &fsm->datagram;
unsigned int i;
ec_slave_t *slave;
ec_master_t *master = fsm->master;
if (datagram->state != EC_DATAGRAM_RECEIVED) {
EC_ERR("Failed to receive broadcast datagram.\n");
fsm->master_state = ec_fsm_error;
return;
}
EC_INFO("Scanning bus.\n");
ec_master_clear_slaves(master);
master->slave_count = datagram->working_counter;
if (!master->slave_count) {
// no slaves present -> finish state machine.
fsm->master_state = ec_fsm_end;
return;
}
// init slaves
for (i = 0; i < master->slave_count; i++) {
if (!(slave = (ec_slave_t *) kmalloc(sizeof(ec_slave_t),
GFP_KERNEL))) {
EC_ERR("Failed to allocate slave %i!\n", i);
fsm->master_state = ec_fsm_error;
return;
}
if (ec_slave_init(slave, master, i, i + 1)) {
fsm->master_state = ec_fsm_error;
return;
}
if (kobject_add(&slave->kobj)) {
EC_ERR("Failed to add kobject.\n");
kobject_put(&slave->kobj); // free
fsm->master_state = ec_fsm_error;
return;
}
list_add_tail(&slave->list, &master->slaves);
}
// begin scanning of slaves
fsm->slave = list_entry(master->slaves.next, ec_slave_t, list);
fsm->slave_state = ec_fsm_slavescan_start;
fsm->master_state = ec_fsm_startup_scan;
fsm->master_state(fsm); // execute immediately
return;
}
/*****************************************************************************/
/**
Master state: SCAN.
Executes the sub-statemachine for the scanning of a slave.
*/
void ec_fsm_startup_scan(ec_fsm_t *fsm /**< finite state machine */)
{
ec_master_t *master = fsm->master;
ec_slave_t *slave = fsm->slave;
fsm->slave_state(fsm); // execute slave state machine
if (fsm->slave_state == ec_fsm_error) {
EC_ERR("Slave scanning failed.\n");
fsm->master_state = ec_fsm_error;
return;
}
if (fsm->slave_state != ec_fsm_end) return;
// another slave to scan?
if (slave->list.next != &master->slaves) {
fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list);
fsm->slave_state = ec_fsm_slavescan_start;
fsm->slave_state(fsm); // execute immediately
return;
}
EC_INFO("Bus scanning completed.\n");
ec_master_calc_addressing(master);
fsm->master_state = ec_fsm_end;
}
/******************************************************************************
* master configuration state machine
*****************************************************************************/
/**
Master configuration state machine: START.
*/
void ec_fsm_configuration_start(ec_fsm_t *fsm /**< finite state machine */)
{
ec_master_t *master = fsm->master;
if (list_empty(&master->slaves)) {
fsm->master_state = ec_fsm_end;
return;
}
// begin configuring slaves
fsm->slave = list_entry(master->slaves.next, ec_slave_t, list);
fsm->slave_state = ec_fsm_slaveconf_init;
ec_fsm_change(&fsm->fsm_change, fsm->slave, EC_SLAVE_STATE_INIT);
fsm->master_state = ec_fsm_configuration_conf;
fsm->master_state(fsm); // execute immediately
}
/*****************************************************************************/
/**
Master state: CONF.
*/
void ec_fsm_configuration_conf(ec_fsm_t *fsm /**< finite state machine */)
{
ec_master_t *master = fsm->master;
ec_slave_t *slave = fsm->slave;
fsm->slave_state(fsm); // execute slave's state machine
if (fsm->slave_state == ec_fsm_error) {
fsm->master_state = ec_fsm_error;
return;
}
if (fsm->slave_state != ec_fsm_end) return;
// another slave to configure?
if (slave->list.next != &master->slaves) {
fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list);
fsm->slave_state = ec_fsm_slaveconf_init;
ec_fsm_change(&fsm->fsm_change, fsm->slave, EC_SLAVE_STATE_INIT);
fsm->master_state(fsm); // execute immediately
return;
}
fsm->master_state = ec_fsm_end;
}
/******************************************************************************
* operation / idle state machine
* operation/idle state machine
*****************************************************************************/
/**
@ -414,8 +187,10 @@ void ec_fsm_master_broadcast(ec_fsm_t *fsm /**< finite state machine */)
slave->online = 0;
}
}
fsm->master_state = ec_fsm_master_start;
fsm->master_state(fsm); // execute immediately
else {
EC_ERR("Failed to receive broadcast datagram.\n");
}
fsm->master_state = ec_fsm_master_error;
return;
}
@ -449,7 +224,6 @@ void ec_fsm_master_broadcast(ec_fsm_t *fsm /**< finite state machine */)
// topology change in idle mode: clear all slaves and scan the bus
if (topology_change && master->mode == EC_MASTER_MODE_IDLE) {
EC_INFO("Scanning bus.\n");
ec_master_eoe_stop(master);
ec_master_clear_slaves(master);
@ -458,8 +232,7 @@ void ec_fsm_master_broadcast(ec_fsm_t *fsm /**< finite state machine */)
if (!master->slave_count) {
// no slaves present -> finish state machine.
fsm->master_state = ec_fsm_master_start;
fsm->master_state(fsm); // execute immediately
fsm->master_state = ec_fsm_master_end;
return;
}
@ -469,16 +242,14 @@ void ec_fsm_master_broadcast(ec_fsm_t *fsm /**< finite state machine */)
GFP_ATOMIC))) {
EC_ERR("Failed to allocate slave %i!\n", i);
ec_master_clear_slaves(master);
fsm->master_state = ec_fsm_master_start;
fsm->master_state(fsm); // execute immediately
fsm->master_state = ec_fsm_master_error;
return;
}
if (ec_slave_init(slave, master, i, i + 1)) {
// freeing of "slave" already done
ec_master_clear_slaves(master);
fsm->master_state = ec_fsm_master_start;
fsm->master_state(fsm); // execute immediately
fsm->master_state = ec_fsm_master_error;
return;
}
@ -486,14 +257,15 @@ void ec_fsm_master_broadcast(ec_fsm_t *fsm /**< finite state machine */)
EC_ERR("Failed to add kobject.\n");
kobject_put(&slave->kobj); // free
ec_master_clear_slaves(master);
fsm->master_state = ec_fsm_master_start;
fsm->master_state(fsm); // execute immediately
fsm->master_state = ec_fsm_master_error;
return;
}
list_add_tail(&slave->list, &master->slaves);
}
EC_INFO("Scanning bus.\n");
// begin scanning of slaves
fsm->slave = list_entry(master->slaves.next, ec_slave_t, list);
fsm->slave_state = ec_fsm_slavescan_start;
@ -533,17 +305,18 @@ void ec_fsm_master_action_process_states(ec_fsm_t *fsm
&& (slave->configured
|| slave->current_state == EC_SLAVE_STATE_INIT))) continue;
ec_state_string(slave->current_state, old_state);
ec_state_string(slave->requested_state, new_state);
if (!slave->configured
&& slave->current_state != EC_SLAVE_STATE_INIT) {
EC_INFO("Reconfiguring slave %i (%s -> %s).\n",
slave->ring_position, old_state, new_state);
}
else if (slave->current_state != slave->requested_state) {
EC_INFO("Changing state of slave %i (%s -> %s).\n",
slave->ring_position, old_state, new_state);
if (master->debug_level) {
ec_state_string(slave->current_state, old_state);
if (!slave->configured
&& slave->current_state != EC_SLAVE_STATE_INIT) {
EC_INFO("Reconfiguring slave %i (%s).\n",
slave->ring_position, old_state);
}
else if (slave->current_state != slave->requested_state) {
ec_state_string(slave->requested_state, new_state);
EC_INFO("Changing state of slave %i (%s -> %s).\n",
slave->ring_position, old_state, new_state);
}
}
fsm->slave = slave;
@ -601,8 +374,7 @@ void ec_fsm_master_action_process_states(ec_fsm_t *fsm
EC_ERR("Failed to add SDO kobj of slave %i.\n",
slave->ring_position);
slave->error_flag = 1;
fsm->master_state = ec_fsm_master_start;
fsm->master_state(fsm); // execute immediately
fsm->master_state = ec_fsm_master_error;
return;
}
@ -639,9 +411,7 @@ void ec_fsm_master_action_process_states(ec_fsm_t *fsm
}
}
// nothing to do. restart master state machine.
fsm->master_state = ec_fsm_master_start;
fsm->master_state(fsm); // execute immediately
fsm->master_state = ec_fsm_master_end;
}
/*****************************************************************************/
@ -702,8 +472,9 @@ void ec_fsm_master_read_states(ec_fsm_t *fsm /**< finite state machine */)
uint8_t new_state;
if (datagram->state != EC_DATAGRAM_RECEIVED) {
fsm->master_state = ec_fsm_master_start;
fsm->master_state(fsm); // execute immediately
EC_ERR("Failed to receive AL state datagram for slave %i!\n",
slave->ring_position);
fsm->master_state = ec_fsm_master_error;
return;
}
@ -756,15 +527,13 @@ void ec_fsm_master_validate_vendor(ec_fsm_t *fsm /**< finite state machine */)
fsm->slave->error_flag = 1;
EC_ERR("Failed to validate vendor ID of slave %i.\n",
slave->ring_position);
fsm->master_state = ec_fsm_master_start;
fsm->master_state(fsm); // execute immediately
fsm->master_state = ec_fsm_master_error;
return;
}
if (EC_READ_U32(fsm->fsm_sii.value) != slave->sii_vendor_id) {
EC_ERR("Slave %i: invalid vendor ID!\n", slave->ring_position);
fsm->master_state = ec_fsm_master_start;
fsm->master_state(fsm); // execute immediately
EC_ERR("Slave %i has an invalid vendor ID!\n", slave->ring_position);
fsm->master_state = ec_fsm_master_error;
return;
}
@ -796,7 +565,8 @@ void ec_fsm_master_action_addresses(ec_fsm_t *fsm /**< finite state machine */)
fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list);
}
EC_INFO("Reinitializing slave %i.\n", fsm->slave->ring_position);
if (fsm->master->debug_level)
EC_DBG("Reinitializing slave %i.\n", fsm->slave->ring_position);
// write station address
ec_datagram_apwr(datagram, fsm->slave->ring_position, 0x0010, 2);
@ -822,8 +592,7 @@ void ec_fsm_master_validate_product(ec_fsm_t *fsm /**< finite state machine */)
fsm->slave->error_flag = 1;
EC_ERR("Failed to validate product code of slave %i.\n",
slave->ring_position);
fsm->master_state = ec_fsm_master_start;
fsm->master_state(fsm); // execute immediately
fsm->master_state = ec_fsm_master_error;
return;
}
@ -831,8 +600,7 @@ void ec_fsm_master_validate_product(ec_fsm_t *fsm /**< finite state machine */)
EC_ERR("Slave %i: invalid product code!\n", slave->ring_position);
EC_ERR("expected 0x%08X, got 0x%08X.\n", slave->sii_product_code,
EC_READ_U32(fsm->fsm_sii.value));
fsm->master_state = ec_fsm_master_start;
fsm->master_state(fsm); // execute immediately
fsm->master_state = ec_fsm_master_error;
return;
}
@ -897,8 +665,8 @@ void ec_fsm_master_scan_slaves(ec_fsm_t *fsm /**< finite state machine */)
fsm->slave_state(fsm); // execute slave state machine
if (fsm->slave_state != ec_fsm_end
&& fsm->slave_state != ec_fsm_error) return;
if (fsm->slave_state != ec_fsm_slave_end
&& fsm->slave_state != ec_fsm_slave_error) return;
// another slave to fetch?
if (slave->list.next != &master->slaves) {
@ -915,11 +683,10 @@ void ec_fsm_master_scan_slaves(ec_fsm_t *fsm /**< finite state machine */)
// set initial states of all slaves to PREOP to make mailbox
// communication possible
list_for_each_entry(slave, &master->slaves, list) {
slave->requested_state = EC_SLAVE_STATE_PREOP;
ec_slave_request_state(slave, EC_SLAVE_STATE_PREOP);
}
fsm->master_state = ec_fsm_master_start;
fsm->master_state(fsm); // execute immediately
fsm->master_state = ec_fsm_master_end;
}
/*****************************************************************************/
@ -935,8 +702,8 @@ void ec_fsm_master_configure_slave(ec_fsm_t *fsm
{
fsm->slave_state(fsm); // execute slave's state machine
if (fsm->slave_state != ec_fsm_end
&& fsm->slave_state != ec_fsm_error) return;
if (fsm->slave_state != ec_fsm_slave_end
&& fsm->slave_state != ec_fsm_slave_error) return;
ec_fsm_master_action_process_states(fsm);
}
@ -959,8 +726,7 @@ void ec_fsm_master_write_eeprom(ec_fsm_t *fsm /**< finite state machine */)
slave->ring_position);
kfree(slave->new_eeprom_data);
slave->new_eeprom_data = NULL;
fsm->master_state = ec_fsm_master_start;
fsm->master_state(fsm); // execute immediately
fsm->master_state = ec_fsm_master_error;
return;
}
@ -999,8 +765,7 @@ void ec_fsm_master_sdodict(ec_fsm_t *fsm /**< finite state machine */)
if (ec_fsm_coe_exec(&fsm->fsm_coe)) return;
if (!ec_fsm_coe_success(&fsm->fsm_coe)) {
fsm->master_state = ec_fsm_master_start;
fsm->master_state(fsm); // execute immediately
fsm->master_state = ec_fsm_master_error;
return;
}
@ -1034,8 +799,7 @@ void ec_fsm_master_sdo_request(ec_fsm_t *fsm /**< finite state machine */)
if (!ec_fsm_coe_success(&fsm->fsm_coe)) {
request->return_code = -1;
master->sdo_seq_master++;
fsm->master_state = ec_fsm_master_start;
fsm->master_state(fsm); // execute immediately
fsm->master_state = ec_fsm_master_error;
return;
}
@ -1049,6 +813,28 @@ void ec_fsm_master_sdo_request(ec_fsm_t *fsm /**< finite state machine */)
fsm->master_state(fsm); // execute immediately
}
/*****************************************************************************/
/**
State: ERROR.
*/
void ec_fsm_master_error(ec_fsm_t *fsm /**< finite state machine */)
{
fsm->master_state = ec_fsm_master_start;
}
/*****************************************************************************/
/**
State: END.
*/
void ec_fsm_master_end(ec_fsm_t *fsm /**< finite state machine */)
{
fsm->master_state = ec_fsm_master_start;
}
/******************************************************************************
* slave scan state machine
*****************************************************************************/
@ -1083,7 +869,7 @@ void ec_fsm_slavescan_address(ec_fsm_t *fsm /**< finite state machine */)
if (datagram->state != EC_DATAGRAM_RECEIVED
|| datagram->working_counter != 1) {
fsm->slave->error_flag = 1;
fsm->slave_state = ec_fsm_error;
fsm->slave_state = ec_fsm_slave_error;
EC_ERR("Failed to write station address of slave %i.\n",
fsm->slave->ring_position);
return;
@ -1109,7 +895,7 @@ void ec_fsm_slavescan_state(ec_fsm_t *fsm /**< finite state machine */)
if (datagram->state != EC_DATAGRAM_RECEIVED
|| datagram->working_counter != 1) {
fsm->slave->error_flag = 1;
fsm->slave_state = ec_fsm_error;
fsm->slave_state = ec_fsm_slave_error;
EC_ERR("Failed to read AL state of slave %i.\n",
fsm->slave->ring_position);
return;
@ -1141,7 +927,7 @@ void ec_fsm_slavescan_base(ec_fsm_t *fsm /**< finite state machine */)
if (datagram->state != EC_DATAGRAM_RECEIVED
|| datagram->working_counter != 1) {
fsm->slave->error_flag = 1;
fsm->slave_state = ec_fsm_error;
fsm->slave_state = ec_fsm_slave_error;
EC_ERR("Failed to read base data of slave %i.\n",
slave->ring_position);
return;
@ -1178,7 +964,7 @@ void ec_fsm_slavescan_datalink(ec_fsm_t *fsm /**< finite state machine */)
if (datagram->state != EC_DATAGRAM_RECEIVED
|| datagram->working_counter != 1) {
fsm->slave->error_flag = 1;
fsm->slave_state = ec_fsm_error;
fsm->slave_state = ec_fsm_slave_error;
EC_ERR("Failed to read DL status of slave %i.\n",
slave->ring_position);
return;
@ -1214,7 +1000,7 @@ void ec_fsm_slavescan_eeprom_size(ec_fsm_t *fsm /**< finite state machine */)
if (!ec_fsm_sii_success(&fsm->fsm_sii)) {
fsm->slave->error_flag = 1;
fsm->slave_state = ec_fsm_error;
fsm->slave_state = ec_fsm_slave_error;
EC_ERR("Failed to read EEPROM size of slave %i.\n",
slave->ring_position);
return;
@ -1242,7 +1028,7 @@ void ec_fsm_slavescan_eeprom_size(ec_fsm_t *fsm /**< finite state machine */)
if (!(slave->eeprom_data =
(uint8_t *) kmalloc(slave->eeprom_size, GFP_ATOMIC))) {
fsm->slave->error_flag = 1;
fsm->slave_state = ec_fsm_error;
fsm->slave_state = ec_fsm_slave_error;
EC_ERR("Failed to allocate EEPROM data on slave %i.\n",
slave->ring_position);
return;
@ -1271,7 +1057,7 @@ void ec_fsm_slavescan_eeprom_data(ec_fsm_t *fsm /**< finite state machine */)
if (!ec_fsm_sii_success(&fsm->fsm_sii)) {
fsm->slave->error_flag = 1;
fsm->slave_state = ec_fsm_error;
fsm->slave_state = ec_fsm_slave_error;
EC_ERR("Failed to fetch EEPROM contents of slave %i.\n",
slave->ring_position);
return;
@ -1359,13 +1145,13 @@ void ec_fsm_slavescan_eeprom_data(ec_fsm_t *fsm /**< finite state machine */)
cat_word += cat_size + 2;
}
fsm->slave_state = ec_fsm_end;
fsm->slave_state = ec_fsm_slave_end;
return;
end:
EC_ERR("Failed to analyze category data.\n");
fsm->slave->error_flag = 1;
fsm->slave_state = ec_fsm_error;
fsm->slave_state = ec_fsm_slave_error;
}
/******************************************************************************
@ -1388,7 +1174,7 @@ void ec_fsm_slaveconf_init(ec_fsm_t *fsm /**< finite state machine */)
if (!ec_fsm_change_success(&fsm->fsm_change)) {
slave->error_flag = 1;
fsm->slave_state = ec_fsm_error;
fsm->slave_state = ec_fsm_slave_error;
return;
}
@ -1400,7 +1186,7 @@ void ec_fsm_slaveconf_init(ec_fsm_t *fsm /**< finite state machine */)
// slave is now in INIT
if (slave->current_state == slave->requested_state) {
fsm->slave_state = ec_fsm_end; // successful
fsm->slave_state = ec_fsm_slave_end; // successful
if (master->debug_level) {
EC_DBG("Finished configuration of slave %i.\n",
slave->ring_position);
@ -1457,7 +1243,7 @@ void ec_fsm_slaveconf_init(ec_fsm_t *fsm /**< finite state machine */)
if (sync->index >= slave->base_sync_count) {
EC_ERR("Invalid sync manager configuration found!");
fsm->slave->error_flag = 1;
fsm->slave_state = ec_fsm_error;
fsm->slave_state = ec_fsm_slave_error;
return;
}
ec_sync_config(sync, slave,
@ -1483,7 +1269,7 @@ void ec_fsm_slaveconf_sync(ec_fsm_t *fsm /**< finite state machine */)
if (datagram->state != EC_DATAGRAM_RECEIVED
|| datagram->working_counter != 1) {
slave->error_flag = 1;
fsm->slave_state = ec_fsm_error;
fsm->slave_state = ec_fsm_slave_error;
EC_ERR("Failed to set sync managers on slave %i.\n",
slave->ring_position);
return;
@ -1511,7 +1297,7 @@ void ec_fsm_slaveconf_preop(ec_fsm_t *fsm /**< finite state machine */)
if (!ec_fsm_change_success(&fsm->fsm_change)) {
slave->error_flag = 1;
fsm->slave_state = ec_fsm_error;
fsm->slave_state = ec_fsm_slave_error;
return;
}
@ -1523,7 +1309,7 @@ void ec_fsm_slaveconf_preop(ec_fsm_t *fsm /**< finite state machine */)
}
if (slave->current_state == slave->requested_state) {
fsm->slave_state = ec_fsm_end; // successful
fsm->slave_state = ec_fsm_slave_end; // successful
if (master->debug_level) {
EC_DBG("Finished configuration of slave %i.\n",
slave->ring_position);
@ -1574,7 +1360,7 @@ void ec_fsm_slaveconf_fmmu(ec_fsm_t *fsm /**< finite state machine */)
if (datagram->state != EC_DATAGRAM_RECEIVED
|| datagram->working_counter != 1) {
fsm->slave->error_flag = 1;
fsm->slave_state = ec_fsm_error;
fsm->slave_state = ec_fsm_slave_error;
EC_ERR("Failed to set FMMUs on slave %i.\n",
fsm->slave->ring_position);
return;
@ -1608,7 +1394,7 @@ void ec_fsm_slaveconf_sdoconf(ec_fsm_t *fsm /**< finite state machine */)
if (!ec_fsm_coe_success(&fsm->fsm_coe)) {
fsm->slave->error_flag = 1;
fsm->slave_state = ec_fsm_error;
fsm->slave_state = ec_fsm_slave_error;
return;
}
@ -1644,7 +1430,7 @@ void ec_fsm_slaveconf_saveop(ec_fsm_t *fsm /**< finite state machine */)
if (!ec_fsm_change_success(&fsm->fsm_change)) {
fsm->slave->error_flag = 1;
fsm->slave_state = ec_fsm_error;
fsm->slave_state = ec_fsm_slave_error;
return;
}
@ -1655,7 +1441,7 @@ void ec_fsm_slaveconf_saveop(ec_fsm_t *fsm /**< finite state machine */)
}
if (fsm->slave->current_state == fsm->slave->requested_state) {
fsm->slave_state = ec_fsm_end; // successful
fsm->slave_state = ec_fsm_slave_end; // successful
if (master->debug_level) {
EC_DBG("Finished configuration of slave %i.\n",
slave->ring_position);
@ -1684,7 +1470,7 @@ void ec_fsm_slaveconf_op(ec_fsm_t *fsm /**< finite state machine */)
if (!ec_fsm_change_success(&fsm->fsm_change)) {
slave->error_flag = 1;
fsm->slave_state = ec_fsm_error;
fsm->slave_state = ec_fsm_slave_error;
return;
}
@ -1695,7 +1481,7 @@ void ec_fsm_slaveconf_op(ec_fsm_t *fsm /**< finite state machine */)
EC_DBG("Finished configuration of slave %i.\n", slave->ring_position);
}
fsm->slave_state = ec_fsm_end; // successful
fsm->slave_state = ec_fsm_slave_end; // successful
}
/******************************************************************************
@ -1706,7 +1492,7 @@ void ec_fsm_slaveconf_op(ec_fsm_t *fsm /**< finite state machine */)
State: ERROR.
*/
void ec_fsm_error(ec_fsm_t *fsm /**< finite state machine */)
void ec_fsm_slave_error(ec_fsm_t *fsm /**< finite state machine */)
{
}
@ -1716,7 +1502,7 @@ void ec_fsm_error(ec_fsm_t *fsm /**< finite state machine */)
State: END.
*/
void ec_fsm_end(ec_fsm_t *fsm /**< finite state machine */)
void ec_fsm_slave_end(ec_fsm_t *fsm /**< finite state machine */)
{
}

View File

@ -84,14 +84,9 @@ struct ec_fsm
int ec_fsm_init(ec_fsm_t *, ec_master_t *);
void ec_fsm_clear(ec_fsm_t *);
void ec_fsm_reset(ec_fsm_t *);
int ec_fsm_exec(ec_fsm_t *);
void ec_fsm_startup(ec_fsm_t *);
int ec_fsm_startup_success(ec_fsm_t *);
void ec_fsm_configuration(ec_fsm_t *);
int ec_fsm_configuration_success(ec_fsm_t *);
int ec_fsm_success(ec_fsm_t *);
/*****************************************************************************/

View File

@ -360,7 +360,7 @@ void ec_fsm_coe_dict_response(ec_fsm_coe_t *fsm /**< finite state machine */)
}
if (mbox_prot != 0x03) { // CoE
EC_WARN("Received mailbox protocol 0x%02X as response.\n", mbox_prot);
EC_ERR("Received mailbox protocol 0x%02X as response.\n", mbox_prot);
fsm->state = ec_fsm_coe_error;
return;
}
@ -549,7 +549,7 @@ void ec_fsm_coe_dict_desc_response(ec_fsm_coe_t *fsm
}
if (mbox_prot != 0x03) { // CoE
EC_WARN("Received mailbox protocol 0x%02X as response.\n", mbox_prot);
EC_ERR("Received mailbox protocol 0x%02X as response.\n", mbox_prot);
fsm->state = ec_fsm_coe_error;
return;
}
@ -722,7 +722,7 @@ void ec_fsm_coe_dict_entry_response(ec_fsm_coe_t *fsm
}
if (mbox_prot != 0x03) { // CoE
EC_WARN("Received mailbox protocol 0x%02X as response.\n", mbox_prot);
EC_ERR("Received mailbox protocol 0x%02X as response.\n", mbox_prot);
fsm->state = ec_fsm_coe_error;
return;
}
@ -970,7 +970,7 @@ void ec_fsm_coe_down_response(ec_fsm_coe_t *fsm /**< finite state machine */)
}
if (mbox_prot != 0x03) { // CoE
EC_WARN("Received mailbox protocol 0x%02X as response.\n", mbox_prot);
EC_ERR("Received mailbox protocol 0x%02X as response.\n", mbox_prot);
fsm->state = ec_fsm_coe_error;
return;
}
@ -1210,8 +1210,10 @@ void ec_fsm_coe_up_response(ec_fsm_coe_t *fsm /**< finite state machine */)
request->size = 0;
if (complete_size) {
if (!(request->data = (uint8_t *) kmalloc(complete_size + 1, GFP_ATOMIC))) {
EC_ERR("Failed to allocate %i bytes of SDO data!\n", complete_size);
if (!(request->data = (uint8_t *)
kmalloc(complete_size + 1, GFP_ATOMIC))) {
EC_ERR("Failed to allocate %i bytes of SDO data!\n",
complete_size);
fsm->state = ec_fsm_coe_error;
return;
}
@ -1228,9 +1230,11 @@ void ec_fsm_coe_up_response(ec_fsm_coe_t *fsm /**< finite state machine */)
fsm->toggle = 0;
if (data_size < complete_size) {
EC_WARN("SDO data incomplete (%i / %i).\n", data_size, complete_size);
EC_WARN("SDO data incomplete (%i / %i).\n",
data_size, complete_size);
if (!(data = ec_slave_mbox_prepare_send(slave, datagram, 0x03, 3))) {
if (!(data = ec_slave_mbox_prepare_send(slave, datagram,
0x03, 3))) {
fsm->state = ec_fsm_coe_error;
return;
}
@ -1354,7 +1358,7 @@ void ec_fsm_coe_up_seg_response(ec_fsm_coe_t *fsm /**< finite state machine */)
}
if (mbox_prot != 0x03) { // CoE
EC_WARN("Received mailbox protocol 0x%02X as response.\n", mbox_prot);
EC_ERR("Received mailbox protocol 0x%02X as response.\n", mbox_prot);
fsm->state = ec_fsm_coe_error;
return;
}

View File

@ -59,6 +59,7 @@ 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);
@ -109,28 +110,55 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT master */
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);
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_timer(&master->eoe_timer);
master->eoe_timer.function = ec_master_eoe_run;
master->eoe_timer.data = (unsigned long) master;
master->eoe_running = 0;
master->eoe_checked = 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 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT master */
return -1;
}
ec_master_reset(master);
return 0;
out_clear_eoe:
@ -203,10 +230,17 @@ 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_datagram_t *datagram, *next_c;
EC_INFO("Clearing master %i...\n", master->index);
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_master_reset(master);
ec_fsm_clear(&master->fsm);
destroy_workqueue(master->workqueue);
ec_xmldev_clear(&master->xmldev);
@ -218,11 +252,6 @@ void ec_master_clear(struct kobject *kobj /**< kobject of the master */)
kfree(eoe);
}
if (master->device) {
ec_device_clear(master->device);
kfree(master->device);
}
EC_INFO("Master %i cleared.\n", master->index);
kfree(master);
@ -230,57 +259,6 @@ void ec_master_clear(struct kobject *kobj /**< kobject of the master */)
/*****************************************************************************/
/**
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 @@ void ec_master_clear_slaves(ec_master_t *master)
kobject_del(&slave->kobj);
kobject_put(&slave->kobj);
}
master->slave_count = 0;
}
@ -314,6 +293,123 @@ void ec_master_flush_sdo_requests(ec_master_t *master)
/*****************************************************************************/
/**
*/
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.
*/
@ -544,32 +640,6 @@ void ec_master_receive_datagrams(ec_master_t *master, /**< EtherCAT master */
/*****************************************************************************/
/**
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
@ -606,52 +676,6 @@ void ec_master_output_stats(ec_master_t *master /**< EtherCAT master */)
/*****************************************************************************/
/**
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 @@ void ec_master_eoe_start(ec_master_t *master /**< EtherCAT master */)
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 @@ void ec_master_eoe_stop(ec_master_t *master /**< EtherCAT master */)
// 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 @@ int ecrt_master_activate(ec_master_t *master /**< EtherCAT master */)
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 @@ void ecrt_master_deactivate(ec_master_t *master /**< EtherCAT master */)
{
ec_fsm_t *fsm = &master->fsm;
ec_slave_t *slave;
ec_datagram_t *datagram = &master->fsm.datagram;
list_for_each_entry(slave, &master->slaves, list) {
slave->requested_state = EC_SLAVE_STATE_INIT;
// 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);
}
ec_fsm_configuration(fsm); // init configuration state machine
// set states for all slaves
list_for_each_entry(slave, &master->slaves, list) {
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 @@ void ecrt_master_prepare(ec_master_t *master /**< EtherCAT master */)
// 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 @@ void ecrt_master_run(ec_master_t *master /**< EtherCAT master */)
// output statistics
ec_master_output_stats(master);
// execute master state machine
// execute master state machine in a loop
ec_fsm_exec(&master->fsm);
}

View File

@ -148,35 +148,31 @@ struct ec_master
/*****************************************************************************/
// master creation and deletion
// master creation
int ec_master_init(ec_master_t *, unsigned int, unsigned int, dev_t);
void ec_master_reset(ec_master_t *);
// free run
void ec_master_idle_start(ec_master_t *);
void ec_master_idle_stop(ec_master_t *);
// mode transitions
int ec_master_enter_idle_mode(ec_master_t *);
void ec_master_leave_idle_mode(ec_master_t *);
int ec_master_enter_operation_mode(ec_master_t *);
void ec_master_leave_operation_mode(ec_master_t *);
// EoE
void ec_master_eoe_start(ec_master_t *);
void ec_master_eoe_stop(ec_master_t *);
// IO
// datagram IO
void ec_master_receive_datagrams(ec_master_t *, const uint8_t *, size_t);
void ec_master_queue_datagram(ec_master_t *, ec_datagram_t *);
// slave management
int ec_master_bus_scan(ec_master_t *);
// misc.
void ec_master_output_stats(ec_master_t *);
void ec_master_clear_slaves(ec_master_t *);
int ec_master_measure_bus_time(ec_master_t *);
void ec_master_calc_addressing(ec_master_t *);
// other methods
// helper functions
void ec_sync_config(const ec_sii_sync_t *, const ec_slave_t *, uint8_t *);
void ec_fmmu_config(const ec_fmmu_t *, const ec_slave_t *, uint8_t *);
void ec_master_calc_addressing(ec_master_t *);
void ec_master_flush_sdo_requests(ec_master_t *);
/*****************************************************************************/

View File

@ -384,7 +384,8 @@ int ecdev_start(unsigned int master_index /**< master index */)
return -1;
}
ec_master_idle_start(master);
ec_master_enter_idle_mode(master);
return 0;
}
@ -402,8 +403,7 @@ void ecdev_stop(unsigned int master_index /**< master index */)
ec_master_t *master;
if (!(master = ec_find_master(master_index))) return;
ec_master_idle_stop(master);
ec_master_flush_sdo_requests(master);
ec_master_leave_idle_mode(master);
if (ec_device_close(master->device))
EC_WARN("Failed to close device!\n");
@ -459,31 +459,19 @@ ec_master_t *ecrt_request_master(unsigned int master_index
goto out_module_put;
}
ec_master_reset(master); // also stops idle mode
master->mode = EC_MASTER_MODE_OPERATION;
if (ec_master_measure_bus_time(master)) {
EC_ERR("Bus time measuring failed!\n");
goto out_reset;
}
if (ec_master_bus_scan(master)) {
EC_ERR("Bus scan failed!\n");
goto out_reset;
if (ec_master_enter_operation_mode(master)) {
EC_ERR("Failed to enter OPERATION mode!\n");
goto out_module_put;
}
EC_INFO("Successfully requested master %i.\n", master_index);
return master;
out_reset:
ec_master_reset(master);
ec_master_idle_start(master);
out_module_put:
module_put(master->device->module);
out_release:
atomic_inc(&master->available);
out_return:
EC_ERR("Failed to request master %i.\n", master_index);
return NULL;
}
@ -496,20 +484,12 @@ ec_master_t *ecrt_request_master(unsigned int master_index
void ecrt_release_master(ec_master_t *master /**< EtherCAT master */)
{
EC_INFO("Releasing master %i...\n", master->index);
if (atomic_read(&master->available)) {
EC_ERR("Master %i was never requested!\n", master->index);
return;
}
ec_master_reset(master);
ec_master_idle_start(master);
ec_master_leave_operation_mode(master);
module_put(master->device->module);
atomic_inc(&master->available);
EC_INFO("Successfully released master %i.\n", master->index);
EC_INFO("Released master %i.\n", master->index);
return;
}

View File

@ -136,7 +136,6 @@ int ec_slave_init(ec_slave_t *slave, /**< EtherCAT slave */
slave->error_flag = 0;
slave->online = 1;
slave->fmmu_count = 0;
slave->registered = 0;
slave->coupler_index = 0;
slave->coupler_subindex = 0xFFFF;
@ -243,7 +242,7 @@ void ec_slave_clear(struct kobject *kobj /**< kobject of the slave */)
kobject_put(&sdo->kobj);
}
// free SDO kobject
// free SDO kobject FIXME
if (slave->sdo_dictionary_fetched) kobject_del(&slave->sdo_kobj);
kobject_put(&slave->sdo_kobj);
@ -262,6 +261,30 @@ void ec_slave_clear(struct kobject *kobj /**< kobject of the slave */)
/*****************************************************************************/
/**
Reset slave from operation mode.
*/
void ec_slave_reset(ec_slave_t *slave /**< EtherCAT slave */)
{
slave->fmmu_count = 0;
}
/*****************************************************************************/
/**
*/
void ec_slave_request_state(ec_slave_t *slave, /**< ETherCAT slave */
ec_slave_state_t state /**< new state */
)
{
slave->requested_state = state;
slave->error_flag = 0;
}
/*****************************************************************************/
/**
Fetches data from a STRING category.
\return 0 in case of success, else < 0
@ -514,7 +537,6 @@ int ec_slave_prepare_fmmu(ec_slave_t *slave, /**< EtherCAT slave */
fmmu->logical_start_address = 0;
slave->fmmu_count++;
slave->registered = 1;
return 0;
}
@ -810,13 +832,13 @@ ssize_t ec_store_slave_attribute(struct kobject *kobj, /**< slave's kobject */
if (attr == &attr_state) {
char state[EC_STATE_STRING_SIZE];
if (!strcmp(buffer, "INIT\n"))
slave->requested_state = EC_SLAVE_STATE_INIT;
ec_slave_request_state(slave, EC_SLAVE_STATE_INIT);
else if (!strcmp(buffer, "PREOP\n"))
slave->requested_state = EC_SLAVE_STATE_PREOP;
ec_slave_request_state(slave, EC_SLAVE_STATE_PREOP);
else if (!strcmp(buffer, "SAVEOP\n"))
slave->requested_state = EC_SLAVE_STATE_SAVEOP;
ec_slave_request_state(slave, EC_SLAVE_STATE_SAVEOP);
else if (!strcmp(buffer, "OP\n"))
slave->requested_state = EC_SLAVE_STATE_OP;
ec_slave_request_state(slave, EC_SLAVE_STATE_OP);
else {
EC_ERR("Invalid slave state \"%s\"!\n", buffer);
return -EINVAL;
@ -825,7 +847,6 @@ ssize_t ec_store_slave_attribute(struct kobject *kobj, /**< slave's kobject */
ec_state_string(slave->requested_state, state);
EC_INFO("Accepted new state %s for slave %i.\n",
state, slave->ring_position);
slave->error_flag = 0;
return size;
}
else if (attr == &attr_eeprom) {

View File

@ -197,10 +197,9 @@ struct ec_slave
ec_slave_state_t requested_state; /**< requested slave state */
ec_slave_state_t current_state; /**< current slave state */
unsigned int configured; /**< the slave is configured by this master */
unsigned int configured; /**< the slave was configured by this master */
unsigned int error_flag; /**< stop processing after an error */
unsigned int online; /**< non-zero, if the slave responds. */
uint8_t registered; /**< true, if slave has been registered */
// addresses
uint16_t ring_position; /**< ring position */
@ -261,9 +260,13 @@ struct ec_slave
// slave construction/destruction
int ec_slave_init(ec_slave_t *, ec_master_t *, uint16_t, uint16_t);
void ec_slave_reset(ec_slave_t *);
int ec_slave_prepare_fmmu(ec_slave_t *, const ec_domain_t *,
const ec_sii_sync_t *);
void ec_slave_request_state(ec_slave_t *, ec_slave_state_t);
// SII categories
int ec_slave_fetch_strings(ec_slave_t *, const uint8_t *);
void ec_slave_fetch_general(ec_slave_t *, const uint8_t *);