# HG changeset patch # User Florian Pose # Date 1148044991 0 # Node ID c1d0b63a93020507bdbacf2c053418dfe8d4cae9 # Parent 440ae5f6d2c3e03ee6639f068ad4b0bbda58ad8f EoE in Free-Run mode; Finished slave configuration state machine. diff -r 440ae5f6d2c3 -r c1d0b63a9302 master/ethernet.c --- a/master/ethernet.c Fri May 19 09:56:55 2006 +0000 +++ b/master/ethernet.c Fri May 19 13:23:11 2006 +0000 @@ -70,17 +70,15 @@ /** EoE constructor. - Initializes the EoE object, creates a net_device and registeres it. -*/ - -int ec_eoe_init(ec_eoe_t *eoe, /**< EoE object */ - ec_slave_t *slave /**< assigned slave */ - ) + Initializes the EoE handler, creates a net_device and registeres it. +*/ + +int ec_eoe_init(ec_eoe_t *eoe /**< EoE handler */) { ec_eoe_t **priv; int result, i; - eoe->slave = slave; + eoe->slave = NULL; eoe->state = ec_eoe_state_rx_start; eoe->opened = 0; eoe->rx_skb = NULL; @@ -95,7 +93,7 @@ if (!(eoe->dev = alloc_netdev(sizeof(ec_eoe_t *), "eoe%d", ether_setup))) { - EC_ERR("Unable to allocate net_device for EoE object!\n"); + EC_ERR("Unable to allocate net_device for EoE handler!\n"); goto out_return; } @@ -145,7 +143,7 @@ Unregisteres the net_device and frees allocated memory. */ -void ec_eoe_clear(ec_eoe_t *eoe /**< EoE object */) +void ec_eoe_clear(ec_eoe_t *eoe /**< EoE handler */) { if (eoe->dev) { unregister_netdev(eoe->dev); @@ -169,7 +167,7 @@ Empties the transmit queue. */ -void ec_eoe_flush(ec_eoe_t *eoe /**< EoE object */) +void ec_eoe_flush(ec_eoe_t *eoe /**< EoE handler */) { ec_eoe_frame_t *frame, *next; @@ -191,7 +189,7 @@ Sends a frame or the next fragment. */ -int ec_eoe_send(ec_eoe_t *eoe /**< EoE object */) +int ec_eoe_send(ec_eoe_t *eoe /**< EoE handler */) { size_t remaining_size, current_size, complete_offset; unsigned int last_fragment; @@ -262,7 +260,7 @@ Runs the EoE state machine. */ -void ec_eoe_run(ec_eoe_t *eoe /**< EoE object */) +void ec_eoe_run(ec_eoe_t *eoe /**< EoE handler */) { if (!eoe->opened) return; @@ -277,22 +275,25 @@ \return 1 if the device is "up", 0 if it is "down" */ -unsigned int ec_eoe_active(const ec_eoe_t *eoe /**< EoE object */) -{ - return eoe->opened; -} - -/*****************************************************************************/ - -/** - Prints EoE object information. -*/ - -void ec_eoe_print(const ec_eoe_t *eoe /**< EoE object */) -{ - EC_INFO(" EoE slave %i\n", eoe->slave->ring_position); - EC_INFO(" Assigned device: %s (%s)\n", eoe->dev->name, - eoe->opened ? "opened" : "closed"); +unsigned int ec_eoe_active(const ec_eoe_t *eoe /**< EoE handler */) +{ + return eoe->slave && eoe->opened; +} + +/*****************************************************************************/ + +/** + Prints EoE handler information. +*/ + +void ec_eoe_print(const ec_eoe_t *eoe /**< EoE handler */) +{ + EC_INFO(" EoE handler %s\n", eoe->dev->name); + EC_INFO(" State: %s\n", eoe->opened ? "opened" : "closed"); + if (eoe->slave) + EC_INFO(" Coupled to slave %i.\n", eoe->slave->ring_position); + else + EC_INFO(" Not coupled.\n"); } /****************************************************************************** @@ -305,7 +306,7 @@ slave's mailbox for a new command. */ -void ec_eoe_state_rx_start(ec_eoe_t *eoe /**< EoE object */) +void ec_eoe_state_rx_start(ec_eoe_t *eoe /**< EoE handler */) { ec_slave_mbox_prepare_check(eoe->slave); ec_master_queue_command(eoe->slave->master, &eoe->slave->mbox_command); @@ -320,7 +321,7 @@ command, if new data is available. */ -void ec_eoe_state_rx_check(ec_eoe_t *eoe /**< EoE object */) +void ec_eoe_state_rx_check(ec_eoe_t *eoe /**< EoE handler */) { if (eoe->slave->mbox_command.state != EC_CMD_RECEIVED) { eoe->stats.rx_errors++; @@ -346,7 +347,7 @@ EoE command. */ -void ec_eoe_state_rx_fetch(ec_eoe_t *eoe /**< EoE object */) +void ec_eoe_state_rx_fetch(ec_eoe_t *eoe /**< EoE handler */) { size_t rec_size, data_size; uint8_t *data, frame_type, last_fragment, time_appended; @@ -486,7 +487,7 @@ sequence is started instead. */ -void ec_eoe_state_tx_start(ec_eoe_t *eoe /**< EoE object */) +void ec_eoe_state_tx_start(ec_eoe_t *eoe /**< EoE handler */) { #if EOE_DEBUG_LEVEL > 0 unsigned int wakeup; @@ -546,7 +547,7 @@ fragment, if necessary. */ -void ec_eoe_state_tx_sent(ec_eoe_t *eoe /**< EoE object */) +void ec_eoe_state_tx_sent(ec_eoe_t *eoe /**< EoE handler */) { if (eoe->slave->mbox_command.state != EC_CMD_RECEIVED) { eoe->stats.tx_errors++; @@ -595,7 +596,12 @@ eoe->opened = 1; netif_start_queue(dev); eoe->tx_queue_active = 1; - EC_INFO("%s (slave %i) opened.\n", dev->name, eoe->slave->ring_position); + EC_INFO("%s opened.\n", dev->name); + 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; + } return 0; } @@ -612,7 +618,12 @@ eoe->tx_queue_active = 0; eoe->opened = 0; ec_eoe_flush(eoe); - EC_INFO("%s (slave %i) stopped.\n", dev->name, eoe->slave->ring_position); + EC_INFO("%s stopped.\n", dev->name); + 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; + } return 0; } diff -r 440ae5f6d2c3 -r c1d0b63a9302 master/ethernet.h --- a/master/ethernet.h Fri May 19 09:56:55 2006 +0000 +++ b/master/ethernet.h Fri May 19 13:23:11 2006 +0000 @@ -64,7 +64,7 @@ typedef struct ec_eoe ec_eoe_t; /** - Ethernet-over-EtherCAT (EoE) Object. + Ethernet-over-EtherCAT (EoE) handler. The master creates one of these objects for each slave that supports the EoE protocol. */ @@ -93,7 +93,7 @@ /*****************************************************************************/ -int ec_eoe_init(ec_eoe_t *, ec_slave_t *); +int ec_eoe_init(ec_eoe_t *); void ec_eoe_clear(ec_eoe_t *); void ec_eoe_run(ec_eoe_t *); unsigned int ec_eoe_active(const ec_eoe_t *); diff -r 440ae5f6d2c3 -r c1d0b63a9302 master/fsm.c --- a/master/fsm.c Fri May 19 09:56:55 2006 +0000 +++ b/master/fsm.c Fri May 19 13:23:11 2006 +0000 @@ -48,21 +48,32 @@ /*****************************************************************************/ +const ec_code_msg_t al_status_messages[]; + +/*****************************************************************************/ + void ec_fsm_master_start(ec_fsm_t *); void ec_fsm_master_wait(ec_fsm_t *); -void ec_fsm_master_slave(ec_fsm_t *); -void ec_fsm_master_calc(ec_fsm_t *); -void ec_fsm_master_finished(ec_fsm_t *); - -void ec_fsm_slave_start(ec_fsm_t *); +void ec_fsm_master_scan(ec_fsm_t *); +void ec_fsm_master_conf(ec_fsm_t *); + +void ec_fsm_slave_start_reading(ec_fsm_t *); void ec_fsm_slave_read_base(ec_fsm_t *); void ec_fsm_slave_read_dl(ec_fsm_t *); void ec_fsm_slave_prepare_sii(ec_fsm_t *); void ec_fsm_slave_read_sii(ec_fsm_t *); -void ec_fsm_slave_categories(ec_fsm_t *); void ec_fsm_slave_category_header(ec_fsm_t *); void ec_fsm_slave_category_data(ec_fsm_t *); -void ec_fsm_slave_finished(ec_fsm_t *); +void ec_fsm_slave_conf(ec_fsm_t *); +void ec_fsm_slave_end(ec_fsm_t *); + +void ec_fsm_slave_conf(ec_fsm_t *); +void ec_fsm_slave_sync(ec_fsm_t *); +void ec_fsm_slave_preop(ec_fsm_t *); +void ec_fsm_slave_fmmu(ec_fsm_t *); +void ec_fsm_slave_saveop(ec_fsm_t *); +void ec_fsm_slave_op(ec_fsm_t *); +void ec_fsm_slave_op2(ec_fsm_t *); void ec_fsm_sii_start_reading(ec_fsm_t *); void ec_fsm_sii_check(ec_fsm_t *); @@ -70,6 +81,15 @@ void ec_fsm_sii_finished(ec_fsm_t *); void ec_fsm_sii_error(ec_fsm_t *); +void ec_fsm_change_start(ec_fsm_t *); +void ec_fsm_change_check(ec_fsm_t *); +void ec_fsm_change_status(ec_fsm_t *); +void ec_fsm_change_code(ec_fsm_t *); +void ec_fsm_change_ack(ec_fsm_t *); +void ec_fsm_change_ack2(ec_fsm_t *); +void ec_fsm_change_end(ec_fsm_t *); +void ec_fsm_change_error(ec_fsm_t *); + /*****************************************************************************/ int ec_fsm_init(ec_fsm_t *fsm, ec_master_t *master) @@ -118,15 +138,6 @@ fsm->master_state(fsm); } -/*****************************************************************************/ - -int ec_fsm_idle(const ec_fsm_t *fsm) -{ - return (fsm->master_state == ec_fsm_master_start || - fsm->master_state == ec_fsm_master_wait || - fsm->master_state == ec_fsm_master_finished); -} - /****************************************************************************** * master state machine *****************************************************************************/ @@ -149,7 +160,7 @@ void ec_fsm_master_wait(ec_fsm_t *fsm) { ec_command_t *command = &fsm->command; - unsigned int first, topology_change, i; + unsigned int topology_change, i, eoe_slaves_active; ec_slave_t *slave; if (command->state != EC_CMD_RECEIVED) { @@ -159,7 +170,42 @@ } if (command->working_counter == fsm->master_slaves_responding && - command->data[0] == fsm->master_slave_states) { + command->data[0] == fsm->master_slave_states) + { + // check if any slaves are not in the state, they're supposed to be + list_for_each_entry(slave, &fsm->master->slaves, list) { + if (slave->state_error || + slave->requested_state == EC_SLAVE_STATE_UNKNOWN || + slave->current_state == slave->requested_state) continue; + + EC_INFO("Changing state of slave %i from ", slave->ring_position); + ec_print_states(slave->current_state); + printk(" to "); + ec_print_states(slave->requested_state); + printk(".\n"); + + fsm->slave = slave; + fsm->slave_state = ec_fsm_slave_conf; + + fsm->change_new = EC_SLAVE_STATE_INIT; + fsm->change_state = ec_fsm_change_start; + + fsm->master_state = ec_fsm_master_conf; + fsm->master_state(fsm); // execute immediately + return; + } + + // nothing to configure... + eoe_slaves_active = 0; + list_for_each_entry(slave, &fsm->master->slaves, list) { + if (slave->sii_mailbox_protocols & EC_MBOX_EOE) { + eoe_slaves_active++; + } + } + + if (eoe_slaves_active && !list_empty(&fsm->master->eoe_handlers)) + ec_master_eoe_start(fsm->master); + fsm->master_state = ec_fsm_master_start; fsm->master_state(fsm); // execute immediately return; @@ -173,26 +219,7 @@ EC_INFO("FSM: %i slave%s responding (", fsm->master_slaves_responding, fsm->master_slaves_responding == 1 ? "" : "s"); - - first = 1; - if (fsm->master_slave_states & EC_SLAVE_STATE_INIT) { - printk("INIT"); - first = 0; - } - if (fsm->master_slave_states & EC_SLAVE_STATE_PREOP) { - if (!first) printk(", "); - printk("PREOP"); - first = 0; - } - if (fsm->master_slave_states & EC_SLAVE_STATE_SAVEOP) { - if (!first) printk(", "); - printk("SAVEOP"); - first = 0; - } - if (fsm->master_slave_states & EC_SLAVE_STATE_OP) { - if (!first) printk(", "); - printk("OP"); - } + ec_print_states(fsm->master_slave_states); printk(")\n"); if (!topology_change || fsm->master->mode == EC_MASTER_MODE_RUNNING) { @@ -201,7 +228,9 @@ return; } - // topology change! + EC_INFO("Topology change detected - Scanning bus.\n"); + + ec_master_eoe_stop(fsm->master); ec_master_clear_slaves(fsm->master); if (!fsm->master_slaves_responding) { @@ -216,19 +245,19 @@ if (!(slave = (ec_slave_t *) kmalloc(sizeof(ec_slave_t), GFP_ATOMIC))) { EC_ERR("FSM failed to allocate slave %i!\n", i); - fsm->master_state = ec_fsm_master_finished; + fsm->master_state = ec_fsm_master_start; return; } if (ec_slave_init(slave, fsm->master, i, i + 1)) { - fsm->master_state = ec_fsm_master_finished; + fsm->master_state = ec_fsm_master_start; return; } if (kobject_add(&slave->kobj)) { EC_ERR("FSM failed to add kobject.\n"); kobject_put(&slave->kobj); // free - fsm->master_state = ec_fsm_master_finished; + fsm->master_state = ec_fsm_master_start; return; } @@ -236,11 +265,10 @@ } // begin scanning of slaves - fsm->slave = list_entry(fsm->master->slaves.next, - ec_slave_t, list); - fsm->slave_state = ec_fsm_slave_start; - - fsm->master_state = ec_fsm_master_slave; + fsm->slave = list_entry(fsm->master->slaves.next, ec_slave_t, list); + fsm->slave_state = ec_fsm_slave_start_reading; + + fsm->master_state = ec_fsm_master_scan; fsm->master_state(fsm); // execute immediately } @@ -251,93 +279,132 @@ Executes the sub-statemachine of a slave. */ -void ec_fsm_master_slave(ec_fsm_t *fsm) +void ec_fsm_master_scan(ec_fsm_t *fsm) { 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_slave_finished) return; + if (fsm->slave_state != ec_fsm_slave_end) return; // have all slaves been fetched? - if (fsm->slave->list.next == &master->slaves) { - fsm->master_state = ec_fsm_master_calc; + if (slave->list.next == &master->slaves) + { + uint16_t coupler_index, coupler_subindex; + uint16_t reverse_coupler_index, current_coupler_index; + ec_slave_t *slave; + ec_slave_ident_t *ident; + + EC_INFO("Bus scanning completed.\n"); + + // identify all slaves and calculate coupler addressing + + coupler_index = 0; + reverse_coupler_index = 0xFFFF; + current_coupler_index = 0x3FFF; + coupler_subindex = 0; + + list_for_each_entry(slave, &master->slaves, list) + { + // search for identification in "database" + ident = slave_idents; + while (ident->type) { + if (ident->vendor_id == slave->sii_vendor_id + && ident->product_code == slave->sii_product_code) { + slave->type = ident->type; + break; + } + ident++; + } + + if (!slave->type) { + EC_WARN("FSM: Unknown slave device (vendor 0x%08X," + " code 0x%08X) at position %i.\n", + slave->sii_vendor_id, slave->sii_product_code, + slave->ring_position); + } + else { + // if the slave is a bus coupler, change adressing base + if (slave->type->special == EC_TYPE_BUS_COUPLER) { + if (slave->sii_alias) + current_coupler_index = reverse_coupler_index--; + else + current_coupler_index = coupler_index++; + coupler_subindex = 0; + } + } + + // determine initial state. + if ((slave->type && slave->type->special == EC_TYPE_BUS_COUPLER)) { + slave->requested_state = EC_SLAVE_STATE_OP; + } + else { + if (master->mode == EC_MASTER_MODE_RUNNING) + slave->requested_state = EC_SLAVE_STATE_PREOP; + else + slave->requested_state = EC_SLAVE_STATE_INIT; + } + + // calculate coupler-based slave address + slave->coupler_index = current_coupler_index; + slave->coupler_subindex = coupler_subindex; + coupler_subindex++; + } + + fsm->master_state = ec_fsm_master_start; fsm->master_state(fsm); // execute immediately return; } // process next slave fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list); - fsm->slave_state = ec_fsm_slave_start; + fsm->slave_state = ec_fsm_slave_start_reading; fsm->slave_state(fsm); // execute immediately } /*****************************************************************************/ /** - Free-Run state: Calc. -*/ - -void ec_fsm_master_calc(ec_fsm_t *fsm) -{ - uint16_t coupler_index, coupler_subindex; - uint16_t reverse_coupler_index, current_coupler_index; + Free-Run state: Configure slaves. +*/ + +void ec_fsm_master_conf(ec_fsm_t *fsm) +{ + ec_master_t *master = fsm->master; ec_slave_t *slave; - ec_slave_ident_t *ident; - ec_master_t *master = fsm->master; - - coupler_index = 0; - reverse_coupler_index = 0xFFFF; - current_coupler_index = 0x3FFF; - coupler_subindex = 0; - - // for every slave on the bus - list_for_each_entry(slave, &master->slaves, list) - { - // search for identification in "database" - ident = slave_idents; - while (ident->type) { - if (unlikely(ident->vendor_id == slave->sii_vendor_id - && ident->product_code == slave->sii_product_code)) { - slave->type = ident->type; - break; - } - ident++; - } - - if (!slave->type) { - EC_WARN("FSM: Unknown slave device (vendor 0x%08X, code 0x%08X) at" - " position %i.\n", slave->sii_vendor_id, - slave->sii_product_code, slave->ring_position); - } - else if (slave->type->special == EC_TYPE_BUS_COUPLER) { - if (slave->sii_alias) - current_coupler_index = reverse_coupler_index--; - else - current_coupler_index = coupler_index++; - coupler_subindex = 0; - } - - slave->coupler_index = current_coupler_index; - slave->coupler_subindex = coupler_subindex; - coupler_subindex++; + + fsm->slave_state(fsm); // execute slave's state machine + + if (fsm->slave_state != ec_fsm_slave_end) return; + + // check if any slaves are not in the state, they're supposed to be + list_for_each_entry(slave, &master->slaves, list) { + if (slave->state_error || + slave->requested_state == EC_SLAVE_STATE_UNKNOWN || + slave->current_state == slave->requested_state) continue; + + EC_INFO("Changing state of slave %i from ", slave->ring_position); + ec_print_states(slave->current_state); + printk(" to "); + ec_print_states(slave->requested_state); + printk(".\n"); + + fsm->slave = slave; + fsm->slave_state = ec_fsm_slave_conf; + + fsm->change_new = EC_SLAVE_STATE_INIT; + fsm->change_state = ec_fsm_change_start; + + fsm->master_state = ec_fsm_master_conf; + fsm->master_state(fsm); // execute immediately + return; } fsm->master_state = ec_fsm_master_start; fsm->master_state(fsm); // execute immediately } -/*****************************************************************************/ - -/** - Free-Run state: Finished. - End state of the state machine. Does nothing. -*/ - -void ec_fsm_master_finished(ec_fsm_t *fsm) -{ -} - /****************************************************************************** * slave state machine *****************************************************************************/ @@ -348,7 +415,7 @@ slave, according to its ring position. */ -void ec_fsm_slave_start(ec_fsm_t *fsm) +void ec_fsm_slave_start_reading(ec_fsm_t *fsm) { ec_command_t *command = &fsm->command; @@ -372,7 +439,7 @@ if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { EC_ERR("FSM failed to write station address of slave %i.\n", fsm->slave->ring_position); - fsm->slave_state = ec_fsm_slave_finished; + fsm->slave_state = ec_fsm_slave_end; return; } @@ -396,7 +463,7 @@ if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { EC_ERR("FSM failed to read base data of slave %i.\n", slave->ring_position); - fsm->slave_state = ec_fsm_slave_finished; + fsm->slave_state = ec_fsm_slave_end; return; } @@ -431,7 +498,7 @@ if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { EC_ERR("FSM failed to read DL status of slave %i.\n", slave->ring_position); - fsm->slave_state = ec_fsm_slave_finished; + fsm->slave_state = ec_fsm_slave_end; return; } @@ -464,7 +531,7 @@ fsm->sii_state(fsm); if (fsm->sii_state == ec_fsm_sii_error) { - fsm->slave_state = ec_fsm_slave_finished; + fsm->slave_state = ec_fsm_slave_end; EC_ERR("FSM failed to read SII data at 0x%04X on slave %i.\n", fsm->sii_offset, slave->ring_position); return; @@ -505,7 +572,27 @@ break; case 7: slave->sii_mailbox_protocols = fsm->sii_result & 0xFFFF; - fsm->slave_state = ec_fsm_slave_categories; + + fsm->slave_cat_offset = 0x0040; + + if (fsm->slave_cat_data) { + EC_INFO("FSM freeing old category data on slave %i...\n", + fsm->slave->ring_position); + kfree(fsm->slave_cat_data); + } + + if (!(fsm->slave_cat_data = + (uint8_t *) kmalloc(EC_CAT_MEM, GFP_ATOMIC))) { + EC_ERR("FSM Failed to allocate category data.\n"); + fsm->slave_state = ec_fsm_slave_end; + return; + } + + // start reading first category header + fsm->sii_offset = fsm->slave_cat_offset; + fsm->sii_state = ec_fsm_sii_start_reading; + + fsm->slave_state = ec_fsm_slave_category_header; fsm->slave_state(fsm); // execute state immediately return; } @@ -518,36 +605,6 @@ /*****************************************************************************/ /** - Slave state: Categories. -*/ - -void ec_fsm_slave_categories(ec_fsm_t *fsm) -{ - fsm->slave_cat_offset = 0x0040; - - if (fsm->slave_cat_data) { - EC_INFO("FSM freeing old category data on slave %i...\n", - fsm->slave->ring_position); - kfree(fsm->slave_cat_data); - } - - if (!(fsm->slave_cat_data = (uint8_t *) kmalloc(EC_CAT_MEM, GFP_ATOMIC))) { - EC_ERR("FSM Failed to allocate category data.\n"); - fsm->slave_state = ec_fsm_slave_finished; - return; - } - - // start reading first category header - fsm->sii_offset = fsm->slave_cat_offset; - fsm->sii_state = ec_fsm_sii_start_reading; - - fsm->slave_state = ec_fsm_slave_category_header; - fsm->slave_state(fsm); // execute state immediately -} - -/*****************************************************************************/ - -/** Slave state: Read categories. Start reading categories. */ @@ -560,7 +617,7 @@ if (fsm->sii_state == ec_fsm_sii_error) { kfree(fsm->slave_cat_data); fsm->slave_cat_data = NULL; - fsm->slave_state = ec_fsm_slave_finished; + fsm->slave_state = ec_fsm_slave_end; EC_ERR("FSM failed to read category header at 0x%04X on slave %i.\n", fsm->slave_cat_offset, fsm->slave->ring_position); return; @@ -572,7 +629,7 @@ if ((fsm->sii_result & 0xFFFF) == 0xFFFF) { kfree(fsm->slave_cat_data); fsm->slave_cat_data = NULL; - fsm->slave_state = ec_fsm_slave_finished; + fsm->slave_state = ec_fsm_slave_end; return; } @@ -582,7 +639,7 @@ if (fsm->slave_cat_words > EC_CAT_MEM * 2) { EC_ERR("FSM category memory too small! %i words needed.\n", fsm->slave_cat_words); - fsm->slave_state = ec_fsm_slave_finished; + fsm->slave_state = ec_fsm_slave_end; return; } @@ -610,7 +667,7 @@ if (fsm->sii_state == ec_fsm_sii_error) { kfree(fsm->slave_cat_data); fsm->slave_cat_data = NULL; - fsm->slave_state = ec_fsm_slave_finished; + fsm->slave_state = ec_fsm_slave_end; EC_ERR("FSM failed to read category 0x%02X data at 0x%04X" " on slave %i.\n", fsm->slave_cat_type, fsm->sii_offset, fsm->slave->ring_position); @@ -690,17 +747,313 @@ out_free: kfree(fsm->slave_cat_data); fsm->slave_cat_data = NULL; - fsm->slave_state = ec_fsm_slave_finished; -} - -/*****************************************************************************/ - -/** - Slave state: Finished. + fsm->slave_state = ec_fsm_slave_end; +} + +/*****************************************************************************/ + +/** + Slave state: Start configuring. +*/ + +void ec_fsm_slave_conf(ec_fsm_t *fsm) +{ + ec_slave_t *slave = fsm->slave; + ec_master_t *master = fsm->master; + ec_command_t *command = &fsm->command; + + fsm->change_state(fsm); // execute state change state machine + + if (fsm->change_state == ec_fsm_change_error) { + fsm->slave_state = ec_fsm_slave_end; + return; + } + + if (fsm->change_state != ec_fsm_change_end) return; + + // slave is now in INIT + if (slave->current_state == slave->requested_state) { + fsm->slave_state = ec_fsm_slave_end; + return; + } + + // check for slave registration + if (!slave->type) { + EC_WARN("Slave %i has unknown type!\n", slave->ring_position); + } + + // check and reset CRC fault counters + //ec_slave_check_crc(slave); + + if (!slave->base_fmmu_count) { // no fmmus + fsm->slave_state = ec_fsm_slave_sync; + fsm->slave_state(fsm); // execute immediately + return; + } + + // reset FMMUs + ec_command_npwr(command, slave->station_address, 0x0600, + EC_FMMU_SIZE * slave->base_fmmu_count); + memset(command->data, 0x00, EC_FMMU_SIZE * slave->base_fmmu_count); + ec_master_queue_command(master, command); + fsm->slave_state = ec_fsm_slave_sync; +} + +/*****************************************************************************/ + +/** + Slave state: Configure sync managers. +*/ + +void ec_fsm_slave_sync(ec_fsm_t *fsm) +{ + ec_command_t *command = &fsm->command; + ec_slave_t *slave = fsm->slave; + unsigned int j; + const ec_sync_t *sync; + ec_eeprom_sync_t *eeprom_sync, mbox_sync; + + if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { + EC_ERR("FSM failed to reset FMMUs of slave %i.\n", + slave->ring_position); + fsm->slave_state = ec_fsm_slave_end; + return; + } + + if (!slave->base_sync_count) { // no sync managers + fsm->slave_state = ec_fsm_slave_preop; + fsm->slave_state(fsm); // execute immediately + return; + } + + // configure sync managers + ec_command_npwr(command, slave->station_address, 0x0800, + EC_SYNC_SIZE * slave->base_sync_count); + memset(command->data, 0x00, EC_SYNC_SIZE * slave->base_sync_count); + + // known slave type, take type's SM information + if (slave->type) { + for (j = 0; slave->type->sync_managers[j] && j < EC_MAX_SYNC; j++) { + sync = slave->type->sync_managers[j]; + ec_sync_config(sync, command->data + EC_SYNC_SIZE * j); + } + } + + // unknown type, but slave has mailbox + else if (slave->sii_mailbox_protocols) + { + // does it supply sync manager configurations in its EEPROM? + if (!list_empty(&slave->eeprom_syncs)) { + list_for_each_entry(eeprom_sync, &slave->eeprom_syncs, list) { + if (eeprom_sync->index >= slave->base_sync_count) { + EC_ERR("Invalid sync manager configuration found!"); + fsm->slave_state = ec_fsm_slave_end; + return; + } + ec_eeprom_sync_config(eeprom_sync, + command->data + EC_SYNC_SIZE + * eeprom_sync->index); + } + } + + // no sync manager information; guess mailbox settings + else { + mbox_sync.physical_start_address = + slave->sii_rx_mailbox_offset; + mbox_sync.length = slave->sii_rx_mailbox_size; + mbox_sync.control_register = 0x26; + mbox_sync.enable = 1; + ec_eeprom_sync_config(&mbox_sync, command->data); + + mbox_sync.physical_start_address = + slave->sii_tx_mailbox_offset; + mbox_sync.length = slave->sii_tx_mailbox_size; + mbox_sync.control_register = 0x22; + mbox_sync.enable = 1; + ec_eeprom_sync_config(&mbox_sync, + command->data + EC_SYNC_SIZE); + } + + EC_INFO("Mailbox configured for unknown slave %i\n", + slave->ring_position); + } + + ec_master_queue_command(fsm->master, command); + fsm->slave_state = ec_fsm_slave_preop; +} + +/*****************************************************************************/ + +/** + Slave state: Change slave state to PREOP. +*/ + +void ec_fsm_slave_preop(ec_fsm_t *fsm) +{ + ec_command_t *command = &fsm->command; + ec_slave_t *slave = fsm->slave; + + if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { + EC_ERR("FSM failed to set sync managers on slave %i.\n", + slave->ring_position); + fsm->slave_state = ec_fsm_slave_end; + return; + } + + fsm->change_new = EC_SLAVE_STATE_PREOP; + fsm->change_state = ec_fsm_change_start; + + fsm->slave_state = ec_fsm_slave_fmmu; + + fsm->change_state(fsm); // execute immediately +} + +/*****************************************************************************/ + +/** + Slave state: Configure FMMUs. +*/ + +void ec_fsm_slave_fmmu(ec_fsm_t *fsm) +{ + ec_slave_t *slave = fsm->slave; + ec_master_t *master = fsm->master; + ec_command_t *command = &fsm->command; + unsigned int j; + + fsm->change_state(fsm); // execute state change state machine + + if (fsm->change_state == ec_fsm_change_error) { + fsm->slave_state = ec_fsm_slave_end; + return; + } + + if (fsm->change_state != ec_fsm_change_end) return; + + // slave is now in PREOP + if (slave->current_state == slave->requested_state) { + fsm->slave_state = ec_fsm_slave_end; + return; + } + + // stop activation here for slaves without type + if (!slave->type) { + fsm->slave_state = ec_fsm_slave_end; + return; + } + +#if 0 + // slaves that are not registered are only brought into PREOP + // state -> nice blinking and mailbox communication possible + if (!slave->registered && !slave->type->special) { + EC_WARN("Slave %i was not registered!\n", slave->ring_position); + fsm->slave_state = ec_fsm_slave_end; + return; + } +#endif + + if (!slave->base_fmmu_count) { + fsm->slave_state = ec_fsm_slave_saveop; + fsm->slave_state(fsm); // execute immediately + return; + } + + // configure FMMUs + ec_command_npwr(command, slave->station_address, + 0x0600, EC_FMMU_SIZE * slave->base_fmmu_count); + memset(command->data, 0x00, EC_FMMU_SIZE * slave->base_fmmu_count); + for (j = 0; j < slave->fmmu_count; j++) { + ec_fmmu_config(&slave->fmmus[j], command->data + EC_FMMU_SIZE * j); + } + + ec_master_queue_command(master, command); + fsm->slave_state = ec_fsm_slave_saveop; +} + +/*****************************************************************************/ + +/** + Slave state: Set slave state to SAVEOP. +*/ + +void ec_fsm_slave_saveop(ec_fsm_t *fsm) +{ + ec_command_t *command = &fsm->command; + + if (fsm->slave->base_fmmu_count && (command->state != EC_CMD_RECEIVED || + command->working_counter != 1)) { + EC_ERR("FSM failed to set FMMUs on slave %i.\n", + fsm->slave->ring_position); + fsm->slave_state = ec_fsm_slave_end; + return; + } + + // set state to SAVEOP + fsm->slave_state = ec_fsm_slave_op; + fsm->change_new = EC_SLAVE_STATE_SAVEOP; + fsm->change_state = ec_fsm_change_start; + fsm->change_state(fsm); // execute immediately +} + +/*****************************************************************************/ + +/** + Slave state: Set slave state to OP. +*/ + +void ec_fsm_slave_op(ec_fsm_t *fsm) +{ + fsm->change_state(fsm); // execute state change state machine + + if (fsm->change_state == ec_fsm_change_error) { + fsm->slave_state = ec_fsm_slave_end; + return; + } + + if (fsm->change_state != ec_fsm_change_end) return; + + // slave is now in SAVEOP + if (fsm->slave->current_state == fsm->slave->requested_state) { + fsm->slave_state = ec_fsm_slave_end; + return; + } + + // set state to OP + fsm->slave_state = ec_fsm_slave_op2; + fsm->change_new = EC_SLAVE_STATE_OP; + fsm->change_state = ec_fsm_change_start; + fsm->change_state(fsm); // execute immediately +} + +/*****************************************************************************/ + +/** + Slave state: Set slave state to OP. +*/ + +void ec_fsm_slave_op2(ec_fsm_t *fsm) +{ + fsm->change_state(fsm); // execute state change state machine + + if (fsm->change_state == ec_fsm_change_error) { + fsm->slave_state = ec_fsm_slave_end; + return; + } + + if (fsm->change_state != ec_fsm_change_end) return; + + // slave is now in OP + fsm->slave_state = ec_fsm_slave_end; +} + +/*****************************************************************************/ + +/** + Slave state: End. End state of the slave state machine. */ -void ec_fsm_slave_finished(ec_fsm_t *fsm) +void ec_fsm_slave_end(ec_fsm_t *fsm) { } @@ -794,4 +1147,238 @@ { } -/*****************************************************************************/ +/****************************************************************************** + * state change state machine + *****************************************************************************/ + +/** + State change state: Start. +*/ + +void ec_fsm_change_start(ec_fsm_t *fsm) +{ + ec_command_t *command = &fsm->command; + ec_slave_t *slave = fsm->slave; + + // write new state to slave + ec_command_npwr(command, slave->station_address, 0x0120, 2); + EC_WRITE_U16(command->data, fsm->change_new); + ec_master_queue_command(fsm->master, command); + fsm->change_state = ec_fsm_change_check; +} + +/*****************************************************************************/ + +/** + State change state: Check. +*/ + +void ec_fsm_change_check(ec_fsm_t *fsm) +{ + ec_command_t *command = &fsm->command; + ec_slave_t *slave = fsm->slave; + + if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { + EC_ERR("FSM: Reception of state command failed.\n"); + slave->state_error = 1; + fsm->change_state = ec_fsm_change_error; + return; + } + + //start = get_cycles(); + //timeout = (cycles_t) 10 * cpu_khz; // 10ms + + // read AL status from slave + ec_command_nprd(command, slave->station_address, 0x0130, 2); + ec_master_queue_command(fsm->master, command); + fsm->change_state = ec_fsm_change_status; +} + +/*****************************************************************************/ + +/** + State change state: Status. +*/ + +void ec_fsm_change_status(ec_fsm_t *fsm) +{ + ec_command_t *command = &fsm->command; + ec_slave_t *slave = fsm->slave; + + if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { + EC_ERR("FSM: Reception of state check command failed.\n"); + slave->state_error = 1; + fsm->change_state = ec_fsm_change_error; + return; + } + + slave->current_state = EC_READ_U8(command->data); + + if (slave->current_state & 0x10) { // state change error + EC_ERR("Failed to set state 0x%02X - Slave %i refused state change" + " (code 0x%02X)!\n", fsm->change_new, slave->ring_position, + slave->current_state); + + fsm->change_new = slave->current_state & 0x0F; + + // fetch AL status error code + ec_command_nprd(command, slave->station_address, 0x0134, 2); + ec_master_queue_command(fsm->master, command); + fsm->change_state = ec_fsm_change_code; + return; + } + + if (slave->current_state == fsm->change_new) { + fsm->change_state = ec_fsm_change_end; + return; + } + + EC_ERR("Failed to check state 0x%02X of slave %i - Timeout!\n", + fsm->change_new, slave->ring_position); + slave->state_error = 1; + fsm->change_state = ec_fsm_change_error; +} + +/*****************************************************************************/ + +/** + State change state: Code. +*/ + +void ec_fsm_change_code(ec_fsm_t *fsm) +{ + ec_command_t *command = &fsm->command; + ec_slave_t *slave = fsm->slave; + uint32_t code; + const ec_code_msg_t *al_msg; + + if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { + EC_ERR("FSM: Reception of AL status code command failed.\n"); + slave->state_error = 1; + fsm->change_state = ec_fsm_change_error; + return; + } + + if ((code = EC_READ_U16(command->data))) { + for (al_msg = al_status_messages; al_msg->code; al_msg++) { + if (al_msg->code != code) continue; + EC_ERR("AL status message 0x%04X: \"%s\".\n", + al_msg->code, al_msg->message); + break; + } + if (!al_msg->code) + EC_ERR("Unknown AL status code 0x%04X.\n", code); + } + + // acknowledge "old" slave state + ec_command_npwr(command, slave->station_address, 0x0120, 2); + EC_WRITE_U16(command->data, slave->current_state); + ec_master_queue_command(fsm->master, command); + fsm->change_state = ec_fsm_change_ack; +} + +/*****************************************************************************/ + +/** + State change state: Acknowledge. +*/ + +void ec_fsm_change_ack(ec_fsm_t *fsm) +{ + ec_command_t *command = &fsm->command; + ec_slave_t *slave = fsm->slave; + + if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { + EC_ERR("FSM: Reception of state ack command failed.\n"); + slave->state_error = 1; + fsm->change_state = ec_fsm_change_error; + return; + } + + // read new AL status + ec_command_nprd(command, slave->station_address, 0x0130, 2); + ec_master_queue_command(fsm->master, command); + fsm->change_state = ec_fsm_change_ack2; +} + +/*****************************************************************************/ + +/** + State change state: Acknowledge 2. +*/ + +void ec_fsm_change_ack2(ec_fsm_t *fsm) +{ + ec_command_t *command = &fsm->command; + ec_slave_t *slave = fsm->slave; + + if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { + EC_ERR("FSM: Reception of state ack check command failed.\n"); + slave->state_error = 1; + fsm->change_state = ec_fsm_change_error; + return; + } + + slave->current_state = EC_READ_U8(command->data); + + if (slave->current_state == fsm->change_new) { + EC_INFO("Acknowleged state 0x%02X on slave %i.\n", + slave->current_state, slave->ring_position); + slave->state_error = 1; + fsm->change_state = ec_fsm_change_error; + return; + } + + EC_WARN("Failed to acknowledge state 0x%02X on slave %i" + " - Timeout!\n", fsm->change_new, slave->ring_position); + slave->state_error = 1; + fsm->change_state = ec_fsm_change_error; +} + +/*****************************************************************************/ + +/** + State change state: End. +*/ + +void ec_fsm_change_end(ec_fsm_t *fsm) +{ +} + +/*****************************************************************************/ + +/** + State change state: Error. +*/ + +void ec_fsm_change_error(ec_fsm_t *fsm) +{ +} + +/*****************************************************************************/ + +/** + Application layer status messages. +*/ + +const ec_code_msg_t al_status_messages[] = { + {0x0001, "Unspecified error"}, + {0x0011, "Invalud requested state change"}, + {0x0012, "Unknown requested state"}, + {0x0013, "Bootstrap not supported"}, + {0x0014, "No valid firmware"}, + {0x0015, "Invalid mailbox configuration"}, + {0x0016, "Invalid mailbox configuration"}, + {0x0017, "Invalid sync manager configuration"}, + {0x0018, "No valid inputs available"}, + {0x0019, "No valid outputs"}, + {0x001A, "Synchronisation error"}, + {0x001B, "Sync manager watchdog"}, + {0x0020, "Slave needs cold start"}, + {0x0021, "Slave needs INIT"}, + {0x0022, "Slave needs PREOP"}, + {0x0023, "Slave needs SAVEOP"}, + {} +}; + +/*****************************************************************************/ diff -r 440ae5f6d2c3 -r c1d0b63a9302 master/fsm.h --- a/master/fsm.h Fri May 19 09:56:55 2006 +0000 +++ b/master/fsm.h Fri May 19 13:23:11 2006 +0000 @@ -76,6 +76,9 @@ void (*sii_state)(ec_fsm_t *); /**< SII state function */ uint16_t sii_offset; /**< input: offset in SII */ uint32_t sii_result; /**< output: read SII value (32bit) */ + + void (*change_state)(ec_fsm_t *); /**< slave state change state function */ + uint8_t change_new; /**< input: new state */ }; /*****************************************************************************/ @@ -84,7 +87,6 @@ void ec_fsm_clear(ec_fsm_t *); void ec_fsm_reset(ec_fsm_t *); void ec_fsm_execute(ec_fsm_t *); -int ec_fsm_idle(const ec_fsm_t *); /*****************************************************************************/ diff -r 440ae5f6d2c3 -r c1d0b63a9302 master/globals.h --- a/master/globals.h Fri May 19 09:56:55 2006 +0000 +++ b/master/globals.h Fri May 19 13:23:11 2006 +0000 @@ -115,6 +115,7 @@ extern void ec_print_data(const uint8_t *, size_t); extern void ec_print_data_diff(const uint8_t *, const uint8_t *, size_t); +extern void ec_print_states(uint8_t); /*****************************************************************************/ diff -r 440ae5f6d2c3 -r c1d0b63a9302 master/master.c --- a/master/master.c Fri May 19 09:56:55 2006 +0000 +++ b/master/master.c Fri May 19 13:23:11 2006 +0000 @@ -56,7 +56,7 @@ /*****************************************************************************/ void ec_master_freerun(void *); -void ec_master_run_eoe(unsigned long); +void ec_master_eoe_run(unsigned long); ssize_t ec_show_master_attribute(struct kobject *, struct attribute *, char *); void ec_master_process_watch_command(ec_master_t *); @@ -94,30 +94,51 @@ */ int ec_master_init(ec_master_t *master, /**< EtherCAT master */ - unsigned int index /**< master index */ + unsigned int index, /**< master index */ + unsigned int eoe_devices /**< number of EoE devices */ ) { + ec_eoe_t *eoe, *next_eoe; + unsigned int i; + EC_INFO("Initializing master %i.\n", index); - if (!(master->workqueue = create_singlethread_workqueue("EoE"))) { - EC_ERR("Failed to create master workqueue.\n"); - goto out_return; - } - - if (ec_fsm_init(&master->fsm, master)) goto out_free_wq; - master->index = index; master->device = NULL; master->reserved = 0; INIT_LIST_HEAD(&master->slaves); INIT_LIST_HEAD(&master->command_queue); INIT_LIST_HEAD(&master->domains); - INIT_LIST_HEAD(&master->eoe_slaves); + INIT_LIST_HEAD(&master->eoe_handlers); ec_command_init(&master->simple_command); INIT_WORK(&master->freerun_work, ec_master_freerun, (void *) master); init_timer(&master->eoe_timer); - master->eoe_timer.function = ec_master_run_eoe; + 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; + + // create workqueue + if (!(master->workqueue = create_singlethread_workqueue("EtherCAT"))) { + EC_ERR("Failed to create master workqueue.\n"); + goto out_return; + } + + // create EoE handlers + for (i = 0; i < eoe_devices; i++) { + if (!(eoe = (ec_eoe_t *) kmalloc(sizeof(ec_eoe_t), GFP_KERNEL))) { + EC_ERR("Failed to allocate EoE-Object.\n"); + goto out_clear_eoe; + } + if (ec_eoe_init(eoe)) { + kfree(eoe); + goto out_clear_eoe; + } + list_add_tail(&eoe->list, &master->eoe_handlers); + } + + // create state machine object + if (ec_fsm_init(&master->fsm, master)) goto out_clear_eoe; // init kobject and add it to the hierarchy memset(&master->kobj, 0x00, sizeof(struct kobject)); @@ -132,7 +153,12 @@ ec_master_reset(master); return 0; - out_free_wq: + out_clear_eoe: + list_for_each_entry_safe(eoe, next_eoe, &master->eoe_handlers, list) { + list_del(&eoe->list); + ec_eoe_clear(eoe); + kfree(eoe); + } destroy_workqueue(master->workqueue); out_return: return -1; @@ -149,6 +175,7 @@ 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); @@ -157,6 +184,13 @@ ec_command_clear(&master->simple_command); destroy_workqueue(master->workqueue); + // clear EoE objects + list_for_each_entry_safe(eoe, next_eoe, &master->eoe_handlers, list) { + list_del(&eoe->list); + ec_eoe_clear(eoe); + kfree(eoe); + } + if (master->device) { ec_device_clear(master->device); kfree(master->device); @@ -177,14 +211,9 @@ { ec_command_t *command, *next_c; ec_domain_t *domain, *next_d; - ec_eoe_t *eoe, *next_eoe; - - // stop EoE processing - del_timer_sync(&master->eoe_timer); - - // stop free-run mode + + ec_master_eoe_stop(master); ec_master_freerun_stop(master); - ec_master_clear_slaves(master); // empty command queue @@ -200,13 +229,6 @@ kobject_put(&domain->kobj); } - // clear EoE objects - list_for_each_entry_safe(eoe, next_eoe, &master->eoe_slaves, list) { - list_del(&eoe->list); - ec_eoe_clear(eoe); - kfree(eoe); - } - master->command_index = 0; master->debug_level = 0; master->timeout = 500; // 500us @@ -674,6 +696,8 @@ { if (master->mode != EC_MASTER_MODE_FREERUN) return; + ec_master_eoe_stop(master); + EC_INFO("Stopping Free-Run mode.\n"); if (!cancel_delayed_work(&master->freerun_work)) { @@ -693,18 +717,21 @@ void ec_master_freerun(void *data /**< master pointer */) { ec_master_t *master = (ec_master_t *) data; - unsigned long delay; + + // aquire master lock + spin_lock_bh(&master->internal_lock); ecrt_master_async_receive(master); - // execute freerun state machine + // execute master state machine ec_fsm_execute(&master->fsm); ecrt_master_async_send(master); - delay = HZ / 100; - if (ec_fsm_idle(&master->fsm)) delay = HZ; - queue_delayed_work(master->workqueue, &master->freerun_work, delay); + // release master lock + spin_unlock_bh(&master->internal_lock); + + queue_delayed_work(master->workqueue, &master->freerun_work, HZ / 100); } /*****************************************************************************/ @@ -799,31 +826,130 @@ /*****************************************************************************/ /** + Starts Ethernet-over-EtherCAT processing for all EoE-capable slaves. +*/ + +void ec_master_eoe_start(ec_master_t *master /**< EtherCAT master */) +{ + ec_eoe_t *eoe; + ec_slave_t *slave; + unsigned int coupled, found; + + if (master->eoe_running) return; + + // decouple all EoE handlers + list_for_each_entry(eoe, &master->eoe_handlers, list) + eoe->slave = NULL; + coupled = 0; + + // couple a free EoE handler to every EoE-capable slave + list_for_each_entry(slave, &master->slaves, list) { + if (!(slave->sii_mailbox_protocols & EC_MBOX_EOE)) continue; + + found = 0; + list_for_each_entry(eoe, &master->eoe_handlers, list) { + if (eoe->slave) continue; + eoe->slave = slave; + found = 1; + 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; + } + + if (!found) { + EC_WARN("No EoE handler for slave %i!\n", slave->ring_position); + slave->requested_state = EC_SLAVE_STATE_INIT; + } + } + + if (!coupled) { + EC_INFO("No EoE handlers coupled.\n"); + return; + } + + EC_INFO("Starting EoE processing.\n"); + master->eoe_running = 1; + + // start EoE processing + master->eoe_timer.expires = jiffies + 10; + add_timer(&master->eoe_timer); + return; +} + +/*****************************************************************************/ + +/** + Stops the Ethernet-over-EtherCAT processing. +*/ + +void ec_master_eoe_stop(ec_master_t *master /**< EtherCAT master */) +{ + ec_eoe_t *eoe; + + if (!master->eoe_running) return; + + EC_INFO("Stopping EoE processing.\n"); + + del_timer_sync(&master->eoe_timer); + + // 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 = NULL; + } + } + + master->eoe_running = 0; +} + +/*****************************************************************************/ + +/** Does the Ethernet-over-EtherCAT processing. */ -void ec_master_run_eoe(unsigned long data /**< master pointer */) +void ec_master_eoe_run(unsigned long data /**< master pointer */) { ec_master_t *master = (ec_master_t *) data; ec_eoe_t *eoe; unsigned int active = 0; - list_for_each_entry(eoe, &master->eoe_slaves, list) { + list_for_each_entry(eoe, &master->eoe_handlers, list) { if (ec_eoe_active(eoe)) active++; } - - // request_cb must return 0, if the lock has been aquired! - if (active && !master->request_cb(master->cb_data)) - { - ecrt_master_async_receive(master); - list_for_each_entry(eoe, &master->eoe_slaves, list) { - ec_eoe_run(eoe); - } - ecrt_master_async_send(master); - + if (!active) goto queue_timer; + + // aquire master lock... + if (master->mode == EC_MASTER_MODE_RUNNING) { + // request_cb must return 0, if the lock has been aquired! + if (master->request_cb(master->cb_data)) + goto queue_timer; + } + else if (master->mode == EC_MASTER_MODE_FREERUN) { + spin_lock(&master->internal_lock); + } + else + goto queue_timer; + + // actual EoE stuff + ecrt_master_async_receive(master); + list_for_each_entry(eoe, &master->eoe_handlers, list) { + ec_eoe_run(eoe); + } + ecrt_master_async_send(master); + + // release lock... + if (master->mode == EC_MASTER_MODE_RUNNING) { master->release_cb(master->cb_data); } - + else if (master->mode == EC_MASTER_MODE_FREERUN) { + spin_unlock(&master->internal_lock); + } + + queue_timer: master->eoe_timer.expires += HZ / EC_EOE_FREQUENCY; add_timer(&master->eoe_timer); } @@ -1404,37 +1530,12 @@ int ecrt_master_start_eoe(ec_master_t *master /**< EtherCAT master */) { - ec_eoe_t *eoe; - ec_slave_t *slave; - if (!master->request_cb || !master->release_cb) { EC_ERR("EoE requires master callbacks to be set!\n"); return -1; } - list_for_each_entry(slave, &master->slaves, list) { - // does the slave support EoE? - if (!(slave->sii_mailbox_protocols & EC_MBOX_EOE)) continue; - - if (!(eoe = (ec_eoe_t *) kmalloc(sizeof(ec_eoe_t), GFP_KERNEL))) { - EC_ERR("Failed to allocate EoE-Object.\n"); - return -1; - } - if (ec_eoe_init(eoe, slave)) { - kfree(eoe); - return -1; - } - list_add_tail(&eoe->list, &master->eoe_slaves); - } - - if (list_empty(&master->eoe_slaves)) { - EC_WARN("start_eoe: no EoE-capable slaves present.\n"); - return 0; - } - - // start EoE processing - master->eoe_timer.expires = jiffies + 10; - add_timer(&master->eoe_timer); + ec_master_eoe_start(master); return 0; } @@ -1482,9 +1583,9 @@ list_for_each_entry(slave, &master->slaves, list) ec_slave_print(slave, verbosity); } - if (!list_empty(&master->eoe_slaves)) { + if (!list_empty(&master->eoe_handlers)) { EC_INFO("Ethernet-over-EtherCAT (EoE) objects:\n"); - list_for_each_entry(eoe, &master->eoe_slaves, list) { + list_for_each_entry(eoe, &master->eoe_handlers, list) { ec_eoe_print(eoe); } } diff -r 440ae5f6d2c3 -r c1d0b63a9302 master/master.h --- a/master/master.h Fri May 19 09:56:55 2006 +0000 +++ b/master/master.h Fri May 19 13:23:11 2006 +0000 @@ -116,7 +116,9 @@ ec_master_mode_t mode; /**< master mode */ struct timer_list eoe_timer; /** EoE timer object */ - struct list_head eoe_slaves; /**< Ethernet-over-EtherCAT slaves */ + unsigned int eoe_running; /**< non-zero, if EoE processing is active. */ + struct list_head eoe_handlers; /**< Ethernet-over-EtherCAT handlers */ + spinlock_t internal_lock; /**< spinlock used in freerun mode */ int (*request_cb)(void *); /**< lock request callback */ void (*release_cb)(void *); /**< lock release callback */ void *cb_data; /**< data parameter of locking callbacks */ @@ -125,7 +127,7 @@ /*****************************************************************************/ // master creation and deletion -int ec_master_init(ec_master_t *, unsigned int); +int ec_master_init(ec_master_t *, unsigned int, unsigned int); void ec_master_clear(struct kobject *); void ec_master_reset(ec_master_t *); @@ -133,6 +135,10 @@ void ec_master_freerun_start(ec_master_t *); void ec_master_freerun_stop(ec_master_t *); +// EoE +void ec_master_eoe_start(ec_master_t *); +void ec_master_eoe_stop(ec_master_t *); + // IO void ec_master_receive(ec_master_t *, const uint8_t *, size_t); void ec_master_queue_command(ec_master_t *, ec_command_t *); @@ -143,6 +149,9 @@ // misc. void ec_master_clear_slaves(ec_master_t *); +void ec_sync_config(const ec_sync_t *, uint8_t *); +void ec_eeprom_sync_config(const ec_eeprom_sync_t *, uint8_t *); +void ec_fmmu_config(const ec_fmmu_t *, uint8_t *); void ec_master_output_stats(ec_master_t *); /*****************************************************************************/ diff -r 440ae5f6d2c3 -r c1d0b63a9302 master/module.c --- a/master/module.c Fri May 19 09:56:55 2006 +0000 +++ b/master/module.c Fri May 19 13:23:11 2006 +0000 @@ -67,19 +67,22 @@ /*****************************************************************************/ static int ec_master_count = 1; +static int ec_eoe_devices = 0; static struct list_head ec_masters; /*****************************************************************************/ /** \cond */ -MODULE_AUTHOR ("Florian Pose "); -MODULE_DESCRIPTION ("EtherCAT master driver module"); +module_param(ec_master_count, int, S_IRUGO); +module_param(ec_eoe_devices, int, S_IRUGO); + +MODULE_AUTHOR("Florian Pose "); +MODULE_DESCRIPTION("EtherCAT master driver module"); MODULE_LICENSE("GPL"); MODULE_VERSION(COMPILE_INFO); - -module_param(ec_master_count, int, 1); MODULE_PARM_DESC(ec_master_count, "number of EtherCAT masters to initialize"); +MODULE_PARM_DESC(ec_eoe_devices, "number of EoE devices per master"); /** \endcond */ @@ -114,7 +117,7 @@ goto out_free; } - if (ec_master_init(master, i)) // kobject_put is done inside... + if (ec_master_init(master, i, ec_eoe_devices)) goto out_free; if (kobject_add(&master->kobj)) { @@ -228,6 +231,41 @@ printk("\n"); } +/*****************************************************************************/ + +/** + Prints slave states in clear text. +*/ + +void ec_print_states(const uint8_t states /**< slave states */) +{ + unsigned int first = 1; + + if (!states) { + printk("(unknown)"); + return; + } + + if (states & EC_SLAVE_STATE_INIT) { + printk("INIT"); + first = 0; + } + if (states & EC_SLAVE_STATE_PREOP) { + if (!first) printk(", "); + printk("PREOP"); + first = 0; + } + if (states & EC_SLAVE_STATE_SAVEOP) { + if (!first) printk(", "); + printk("SAVEOP"); + first = 0; + } + if (states & EC_SLAVE_STATE_OP) { + if (!first) printk(", "); + printk("OP"); + } +} + /****************************************************************************** * Device interface *****************************************************************************/ diff -r 440ae5f6d2c3 -r c1d0b63a9302 master/slave.c --- a/master/slave.c Fri May 19 09:56:55 2006 +0000 +++ b/master/slave.c Fri May 19 13:23:11 2006 +0000 @@ -48,6 +48,10 @@ /*****************************************************************************/ +extern const ec_code_msg_t al_status_messages[]; + +/*****************************************************************************/ + int ec_slave_fetch_categories(ec_slave_t *); ssize_t ec_show_slave_attribute(struct kobject *, struct attribute *, char *); @@ -89,10 +93,6 @@ /*****************************************************************************/ -const ec_code_msg_t al_status_messages[]; - -/*****************************************************************************/ - /** Slave constructor. \return 0 in case of success, else < 0 @@ -144,6 +144,9 @@ slave->eeprom_name = NULL; slave->eeprom_group = NULL; slave->eeprom_desc = NULL; + slave->requested_state = EC_SLAVE_STATE_UNKNOWN; + slave->current_state = EC_SLAVE_STATE_UNKNOWN; + slave->state_error = 0; ec_command_init(&slave->mbox_command); @@ -1261,32 +1264,6 @@ return 0; } -/*****************************************************************************/ - -/** - Application layer status messages. -*/ - -const ec_code_msg_t al_status_messages[] = { - {0x0001, "Unspecified error"}, - {0x0011, "Invalud requested state change"}, - {0x0012, "Unknown requested state"}, - {0x0013, "Bootstrap not supported"}, - {0x0014, "No valid firmware"}, - {0x0015, "Invalid mailbox configuration"}, - {0x0016, "Invalid mailbox configuration"}, - {0x0017, "Invalid sync manager configuration"}, - {0x0018, "No valid inputs available"}, - {0x0019, "No valid outputs"}, - {0x001A, "Synchronisation error"}, - {0x001B, "Sync manager watchdog"}, - {0x0020, "Slave needs cold start"}, - {0x0021, "Slave needs INIT"}, - {0x0022, "Slave needs PREOP"}, - {0x0023, "Slave needs SAVEOP"}, - {} -}; - /****************************************************************************** * Realtime interface *****************************************************************************/ diff -r 440ae5f6d2c3 -r c1d0b63a9302 master/slave.h --- a/master/slave.h Fri May 19 09:56:55 2006 +0000 +++ b/master/slave.h Fri May 19 13:23:11 2006 +0000 @@ -272,6 +272,10 @@ struct list_head sdo_dictionary; /**< SDO directory list */ ec_command_t mbox_command; /**< mailbox command */ + + ec_slave_state_t requested_state; /**< requested slave state */ + ec_slave_state_t current_state; /**< current slave state */ + unsigned int state_error; /**< a state error has happened */ }; /*****************************************************************************/ diff -r 440ae5f6d2c3 -r c1d0b63a9302 script/ethercat.sh --- a/script/ethercat.sh Fri May 19 09:56:55 2006 +0000 +++ b/script/ethercat.sh Fri May 19 13:23:11 2006 +0000 @@ -73,6 +73,10 @@ rc_exit fi + if [ ! $EOE_DEVICES ]; then + EOE_DEVICES=0 + fi + for mod in 8139too 8139cp; do if lsmod | grep "^$mod " > /dev/null; then if ! rmmod $mod; then @@ -83,7 +87,17 @@ fi done - modprobe ec_8139too ec_device_index=$DEVICE_INDEX + if ! modprobe ec_master ec_eoe_devices=$EOE_DEVICES; then + /bin/false + rc_status -v + rc_exit + fi + + if ! modprobe ec_8139too ec_device_index=$DEVICE_INDEX; then + /bin/false + rc_status -v + rc_exit + fi rc_status -v ;; diff -r 440ae5f6d2c3 -r c1d0b63a9302 script/sysconfig --- a/script/sysconfig Fri May 19 09:56:55 2006 +0000 +++ b/script/sysconfig Fri May 19 13:23:11 2006 +0000 @@ -13,7 +13,7 @@ #DEVICE_INDEX=99 # -# Number of Ethernet-over-EtherCAT devices the master shall create +# Number of Ethernet-over-EtherCAT devices every master shall create # on startup. Default is 0. # #EOE_DEVICES=0