diff -r 3eea08638522 -r f789bdd78b54 master/fsm.c --- a/master/fsm.c Wed Jan 10 10:58:49 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1831 +0,0 @@ -/****************************************************************************** - * - * $Id$ - * - * Copyright (C) 2006 Florian Pose, Ingenieurgemeinschaft IgH - * - * This file is part of the IgH EtherCAT Master. - * - * The IgH EtherCAT Master is free software; you can redistribute it - * and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * The IgH EtherCAT Master is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the IgH EtherCAT Master; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * The right to use EtherCAT Technology is granted and comes free of - * charge under condition of compatibility of product made by - * Licensee. People intending to distribute/sell products based on the - * code, have to sign an agreement to guarantee that products using - * software based on IgH EtherCAT master stay compatible with the actual - * EtherCAT specification (which are released themselves as an open - * standard) as the (only) precondition to have the right to use EtherCAT - * Technology, IP and trade marks. - * - *****************************************************************************/ - -/** - \file - EtherCAT finite state machines. -*/ - -/*****************************************************************************/ - -#include "globals.h" -#include "fsm.h" -#include "master.h" -#include "mailbox.h" - -/*****************************************************************************/ - -void ec_fsm_master_start(ec_fsm_t *); -void ec_fsm_master_broadcast(ec_fsm_t *); -void ec_fsm_master_read_states(ec_fsm_t *); -void ec_fsm_master_acknowledge(ec_fsm_t *); -void ec_fsm_master_validate_vendor(ec_fsm_t *); -void ec_fsm_master_validate_product(ec_fsm_t *); -void ec_fsm_master_rewrite_addresses(ec_fsm_t *); -void ec_fsm_master_configure_slave(ec_fsm_t *); -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_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 *); -void ec_fsm_slavescan_state(ec_fsm_t *); -void ec_fsm_slavescan_base(ec_fsm_t *); -void ec_fsm_slavescan_datalink(ec_fsm_t *); -void ec_fsm_slavescan_eeprom_size(ec_fsm_t *); -void ec_fsm_slavescan_eeprom_data(ec_fsm_t *); - -void ec_fsm_slaveconf_state_start(ec_fsm_t *); -void ec_fsm_slaveconf_state_init(ec_fsm_t *); -void ec_fsm_slaveconf_state_clear_fmmus(ec_fsm_t *); -void ec_fsm_slaveconf_state_sync(ec_fsm_t *); -void ec_fsm_slaveconf_state_preop(ec_fsm_t *); -void ec_fsm_slaveconf_state_sync2(ec_fsm_t *); -void ec_fsm_slaveconf_state_fmmu(ec_fsm_t *); -void ec_fsm_slaveconf_state_sdoconf(ec_fsm_t *); -void ec_fsm_slaveconf_state_saveop(ec_fsm_t *); -void ec_fsm_slaveconf_state_op(ec_fsm_t *); - -void ec_fsm_slaveconf_enter_sync(ec_fsm_t *); -void ec_fsm_slaveconf_enter_preop(ec_fsm_t *); -void ec_fsm_slaveconf_enter_sync2(ec_fsm_t *); -void ec_fsm_slaveconf_enter_fmmu(ec_fsm_t *); -void ec_fsm_slaveconf_enter_sdoconf(ec_fsm_t *); -void ec_fsm_slaveconf_enter_saveop(ec_fsm_t *); - -void ec_fsm_slave_state_end(ec_fsm_t *); -void ec_fsm_slave_state_error(ec_fsm_t *); - -/*****************************************************************************/ - -/** - Constructor. -*/ - -int ec_fsm_init(ec_fsm_t *fsm, /**< finite state machine */ - ec_master_t *master /**< EtherCAT master */ - ) -{ - fsm->master = master; - fsm->master_state = ec_fsm_master_start; - fsm->master_slaves_responding = 0; - fsm->master_slave_states = EC_SLAVE_STATE_UNKNOWN; - fsm->master_validation = 0; - - ec_datagram_init(&fsm->datagram); - if (ec_datagram_prealloc(&fsm->datagram, EC_MAX_DATA_SIZE)) { - EC_ERR("Failed to allocate FSM datagram.\n"); - return -1; - } - - // init sub-state-machines - ec_fsm_sii_init(&fsm->fsm_sii, &fsm->datagram); - ec_fsm_change_init(&fsm->fsm_change, &fsm->datagram); - ec_fsm_coe_init(&fsm->fsm_coe, &fsm->datagram); - - return 0; -} - -/*****************************************************************************/ - -/** - Destructor. -*/ - -void ec_fsm_clear(ec_fsm_t *fsm /**< finite state machine */) -{ - // clear sub-state machines - ec_fsm_sii_clear(&fsm->fsm_sii); - ec_fsm_change_clear(&fsm->fsm_change); - ec_fsm_coe_clear(&fsm->fsm_coe); - - ec_datagram_clear(&fsm->datagram); -} - -/*****************************************************************************/ - -/** - Executes the current state of the state machine. - If the state machine's datagram is not sent or received yet, the execution - of the state machine is delayed to the next cycle. - \return false, if state machine has terminated -*/ - -int ec_fsm_exec(ec_fsm_t *fsm /**< finite state machine */) -{ - if (fsm->datagram.state == EC_DATAGRAM_SENT - || fsm->datagram.state == EC_DATAGRAM_QUEUED) { - // datagram was not sent or received yet. - return ec_fsm_running(fsm); - } - - fsm->master_state(fsm); - return ec_fsm_running(fsm); -} - -/*****************************************************************************/ - -/** - \return false, if state machine has terminated -*/ - -int ec_fsm_running(ec_fsm_t *fsm /**< finite state machine */) -{ - return fsm->master_state != ec_fsm_master_end - && fsm->master_state != ec_fsm_master_error; -} - -/*****************************************************************************/ - -/** - \return true, if the master state machine terminated gracefully -*/ - -int ec_fsm_success(ec_fsm_t *fsm /**< finite state machine */) -{ - return fsm->master_state == ec_fsm_master_end; -} - -/****************************************************************************** - * operation/idle state machine - *****************************************************************************/ - -/** - Master state: START. - Starts with getting slave count and slave states. -*/ - -void ec_fsm_master_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_master_broadcast; -} - -/*****************************************************************************/ - -/** - Master state: BROADCAST. - Processes the broadcast read slave count and slaves states. -*/ - -void ec_fsm_master_broadcast(ec_fsm_t *fsm /**< finite state machine */) -{ - ec_datagram_t *datagram = &fsm->datagram; - unsigned int topology_change, states_change, i; - ec_slave_t *slave; - ec_master_t *master = fsm->master; - - if (datagram->state == EC_DATAGRAM_TIMED_OUT) { - // always retry - ec_master_queue_datagram(fsm->master, &fsm->datagram); - return; - } - - if (datagram->state != EC_DATAGRAM_RECEIVED) { // EC_DATAGRAM_ERROR - // link is down - fsm->master_slaves_responding = 0; - list_for_each_entry(slave, &master->slaves, list) { - slave->online = 0; - } - fsm->master_state = ec_fsm_master_error; - return; - } - - topology_change = (datagram->working_counter != - fsm->master_slaves_responding); - states_change = (EC_READ_U8(datagram->data) != fsm->master_slave_states); - - fsm->master_slave_states = EC_READ_U8(datagram->data); - fsm->master_slaves_responding = datagram->working_counter; - - if (topology_change) { - EC_INFO("%i slave%s responding.\n", - fsm->master_slaves_responding, - fsm->master_slaves_responding == 1 ? "" : "s"); - - if (master->mode == EC_MASTER_MODE_OPERATION) { - if (fsm->master_slaves_responding == master->slave_count) { - fsm->master_validation = 1; // start validation later - } - else { - EC_WARN("Invalid slave count. Bus in tainted state.\n"); - } - } - } - - if (states_change) { - char states[EC_STATE_STRING_SIZE]; - ec_state_string(fsm->master_slave_states, states); - EC_INFO("Slave states: %s.\n", states); - } - - // topology change in idle mode: clear all slaves and scan the bus - if (topology_change && master->mode == EC_MASTER_MODE_IDLE) { - - ec_master_eoe_stop(master); - ec_master_destroy_slaves(master); - - master->slave_count = datagram->working_counter; - - if (!master->slave_count) { - // no slaves present -> finish state machine. - fsm->master_state = ec_fsm_master_end; - return; - } - - // init slaves - for (i = 0; i < master->slave_count; i++) { - if (!(slave = (ec_slave_t *) kmalloc(sizeof(ec_slave_t), - GFP_ATOMIC))) { - EC_ERR("Failed to allocate slave %i!\n", i); - ec_master_destroy_slaves(master); - fsm->master_state = ec_fsm_master_error; - return; - } - - if (ec_slave_init(slave, master, i, i + 1)) { - // freeing of "slave" already done - ec_master_destroy_slaves(master); - 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; - fsm->master_state = ec_fsm_master_scan_slaves; - fsm->master_state(fsm); // execute immediately - return; - } - - // fetch state from each slave - fsm->slave = list_entry(master->slaves.next, ec_slave_t, list); - ec_datagram_nprd(&fsm->datagram, fsm->slave->station_address, 0x0130, 2); - ec_master_queue_datagram(master, &fsm->datagram); - fsm->retries = EC_FSM_RETRIES; - fsm->master_state = ec_fsm_master_read_states; -} - -/*****************************************************************************/ - -/** - Master action: PROC_STATES. - Processes the slave states. -*/ - -void ec_fsm_master_action_process_states(ec_fsm_t *fsm - /**< finite state machine */ - ) -{ - ec_master_t *master = fsm->master; - ec_slave_t *slave; - char old_state[EC_STATE_STRING_SIZE], new_state[EC_STATE_STRING_SIZE]; - - // check if any slaves are not in the state, they're supposed to be - list_for_each_entry(slave, &master->slaves, list) { - if (slave->error_flag - || !slave->online - || slave->requested_state == EC_SLAVE_STATE_UNKNOWN - || (slave->current_state == slave->requested_state - && slave->self_configured)) continue; - - if (master->debug_level) { - ec_state_string(slave->current_state, old_state); - if (slave->current_state != slave->requested_state) { - ec_state_string(slave->requested_state, new_state); - EC_DBG("Changing state of slave %i (%s -> %s).\n", - slave->ring_position, old_state, new_state); - } - else if (!slave->self_configured) { - EC_DBG("Reconfiguring slave %i (%s).\n", - slave->ring_position, old_state); - } - } - - fsm->master_state = ec_fsm_master_configure_slave; - fsm->slave = slave; - fsm->slave_state = ec_fsm_slaveconf_state_start; - fsm->slave_state(fsm); // execute immediately - return; - } - - // Check, if EoE processing has to be started - ec_master_eoe_start(master); - - if (master->mode == EC_MASTER_MODE_IDLE) { - - // Check for a pending SDO request - if (master->sdo_seq_master != master->sdo_seq_user) { - if (master->debug_level) - EC_DBG("Processing SDO request...\n"); - slave = master->sdo_request->sdo->slave; - if (slave->current_state == EC_SLAVE_STATE_INIT - || !slave->online) { - EC_ERR("Failed to process SDO request, slave %i not ready.\n", - slave->ring_position); - master->sdo_request->return_code = -1; - master->sdo_seq_master++; - } - else { - // start uploading SDO - fsm->slave = slave; - fsm->master_state = ec_fsm_master_sdo_request; - fsm->sdo_request = master->sdo_request; - ec_fsm_coe_upload(&fsm->fsm_coe, slave, fsm->sdo_request); - ec_fsm_coe_exec(&fsm->fsm_coe); // execute immediately - return; - } - } - - // check, if slaves have an SDO dictionary to read out. - list_for_each_entry(slave, &master->slaves, list) { - if (!(slave->sii_mailbox_protocols & EC_MBOX_COE) - || slave->sdo_dictionary_fetched - || slave->current_state == EC_SLAVE_STATE_INIT - || jiffies - slave->jiffies_preop < EC_WAIT_SDO_DICT * HZ - || !slave->online - || slave->error_flag) continue; - - if (master->debug_level) { - EC_DBG("Fetching SDO dictionary from slave %i.\n", - slave->ring_position); - } - - slave->sdo_dictionary_fetched = 1; - - // start fetching SDO dictionary - fsm->slave = slave; - fsm->master_state = ec_fsm_master_sdodict; - ec_fsm_coe_dictionary(&fsm->fsm_coe, slave); - ec_fsm_coe_exec(&fsm->fsm_coe); // execute immediately - return; - } - - // check for pending EEPROM write operations. - list_for_each_entry(slave, &master->slaves, list) { - if (!slave->new_eeprom_data) continue; - - if (!slave->online || slave->error_flag) { - kfree(slave->new_eeprom_data); - slave->new_eeprom_data = NULL; - EC_ERR("Discarding EEPROM data, slave %i not ready.\n", - slave->ring_position); - continue; - } - - // found pending EEPROM write operation. execute it! - EC_INFO("Writing EEPROM of slave %i...\n", slave->ring_position); - fsm->slave = slave; - fsm->sii_offset = 0x0000; - ec_fsm_sii_write(&fsm->fsm_sii, slave, fsm->sii_offset, - slave->new_eeprom_data, EC_FSM_SII_NODE); - fsm->master_state = ec_fsm_master_write_eeprom; - fsm->master_state(fsm); // execute immediately - return; - } - } - - fsm->master_state = ec_fsm_master_end; -} - -/*****************************************************************************/ - -/** - Master action: Get state of next slave. -*/ - -void ec_fsm_master_action_next_slave_state(ec_fsm_t *fsm - /**< finite state machine */) -{ - ec_master_t *master = fsm->master; - ec_slave_t *slave = fsm->slave; - - // is there another slave to query? - if (slave->list.next != &master->slaves) { - // process next slave - fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list); - ec_datagram_nprd(&fsm->datagram, fsm->slave->station_address, - 0x0130, 2); - ec_master_queue_datagram(master, &fsm->datagram); - fsm->retries = EC_FSM_RETRIES; - fsm->master_state = ec_fsm_master_read_states; - return; - } - - // all slave states read - - // check, if a bus validation has to be done - if (fsm->master_validation) { - fsm->master_validation = 0; - list_for_each_entry(slave, &master->slaves, list) { - if (slave->online) continue; - - // At least one slave is offline. validate! - EC_INFO("Validating bus.\n"); - fsm->slave = list_entry(master->slaves.next, ec_slave_t, list); - fsm->master_state = ec_fsm_master_validate_vendor; - ec_fsm_sii_read(&fsm->fsm_sii, slave, 0x0008, EC_FSM_SII_POSITION); - ec_fsm_sii_exec(&fsm->fsm_sii); // execute immediately - return; - } - } - - ec_fsm_master_action_process_states(fsm); -} - -/*****************************************************************************/ - -/** - Master state: READ STATES. - Fetches the AL- and online state of a slave. -*/ - -void ec_fsm_master_read_states(ec_fsm_t *fsm /**< finite state machine */) -{ - ec_slave_t *slave = fsm->slave; - ec_datagram_t *datagram = &fsm->datagram; - uint8_t new_state; - - if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) { - ec_master_queue_datagram(fsm->master, &fsm->datagram); - return; - } - - if (datagram->state != EC_DATAGRAM_RECEIVED) { - EC_ERR("Failed to receive AL state datagram for slave %i!\n", - slave->ring_position); - fsm->master_state = ec_fsm_master_error; - return; - } - - // did the slave not respond to its station address? - if (datagram->working_counter != 1) { - if (slave->online) { - slave->online = 0; - if (slave->master->debug_level) - EC_DBG("Slave %i: offline.\n", slave->ring_position); - } - ec_fsm_master_action_next_slave_state(fsm); - return; - } - - // slave responded - new_state = EC_READ_U8(datagram->data); - if (!slave->online) { // slave was offline before - slave->online = 1; - slave->error_flag = 0; // clear error flag - slave->current_state = new_state; - if (slave->master->debug_level) { - char cur_state[EC_STATE_STRING_SIZE]; - ec_state_string(slave->current_state, cur_state); - EC_DBG("Slave %i: online (%s).\n", - slave->ring_position, cur_state); - } - } - else if (new_state != slave->current_state) { - if (slave->master->debug_level) { - char old_state[EC_STATE_STRING_SIZE], - cur_state[EC_STATE_STRING_SIZE]; - ec_state_string(slave->current_state, old_state); - ec_state_string(new_state, cur_state); - EC_DBG("Slave %i: %s -> %s.\n", - slave->ring_position, old_state, cur_state); - } - slave->current_state = new_state; - } - - // check, if new slave state has to be acknowledged - if (slave->current_state & EC_SLAVE_STATE_ACK_ERR && !slave->error_flag) { - ec_fsm_change_ack(&fsm->fsm_change, slave); - ec_fsm_change_exec(&fsm->fsm_change); - fsm->master_state = ec_fsm_master_acknowledge; - return; - } - - ec_fsm_master_action_next_slave_state(fsm); -} - -/*****************************************************************************/ - -/** - Master state: ACKNOWLEDGE -*/ - -void ec_fsm_master_acknowledge(ec_fsm_t *fsm /**< finite state machine */) -{ - ec_slave_t *slave = fsm->slave; - - if (ec_fsm_change_exec(&fsm->fsm_change)) return; - - if (!ec_fsm_change_success(&fsm->fsm_change)) { - fsm->slave->error_flag = 1; - EC_ERR("Failed to acknowledge state change on slave %i.\n", - slave->ring_position); - fsm->master_state = ec_fsm_master_error; - return; - } - - ec_fsm_master_action_next_slave_state(fsm); -} - -/*****************************************************************************/ - -/** - Master state: VALIDATE_VENDOR. - Validates the vendor ID of a slave. -*/ - -void ec_fsm_master_validate_vendor(ec_fsm_t *fsm /**< finite state machine */) -{ - ec_slave_t *slave = fsm->slave; - - if (ec_fsm_sii_exec(&fsm->fsm_sii)) return; - - if (!ec_fsm_sii_success(&fsm->fsm_sii)) { - 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_error; - return; - } - - if (EC_READ_U32(fsm->fsm_sii.value) != slave->sii_vendor_id) { - EC_ERR("Slave %i has an invalid vendor ID!\n", slave->ring_position); - fsm->master_state = ec_fsm_master_error; - return; - } - - // vendor ID is ok. check product code. - fsm->master_state = ec_fsm_master_validate_product; - ec_fsm_sii_read(&fsm->fsm_sii, slave, 0x000A, EC_FSM_SII_POSITION); - ec_fsm_sii_exec(&fsm->fsm_sii); // execute immediately -} - -/*****************************************************************************/ - -/** - Master action: ADDRESS. - Looks for slave, that have lost their configuration and writes - their station address, so that they can be reconfigured later. -*/ - -void ec_fsm_master_action_addresses(ec_fsm_t *fsm /**< finite state machine */) -{ - ec_datagram_t *datagram = &fsm->datagram; - - while (fsm->slave->online) { - if (fsm->slave->list.next == &fsm->master->slaves) { // last slave? - fsm->master_state = ec_fsm_master_start; - fsm->master_state(fsm); // execute immediately - return; - } - // check next slave - fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list); - } - - 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); - EC_WRITE_U16(datagram->data, fsm->slave->station_address); - ec_master_queue_datagram(fsm->master, datagram); - fsm->retries = EC_FSM_RETRIES; - fsm->master_state = ec_fsm_master_rewrite_addresses; -} - -/*****************************************************************************/ - -/** - Master state: VALIDATE_PRODUCT. - Validates the product ID of a slave. -*/ - -void ec_fsm_master_validate_product(ec_fsm_t *fsm /**< finite state machine */) -{ - ec_slave_t *slave = fsm->slave; - - if (ec_fsm_sii_exec(&fsm->fsm_sii)) return; - - if (!ec_fsm_sii_success(&fsm->fsm_sii)) { - 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_error; - return; - } - - if (EC_READ_U32(fsm->fsm_sii.value) != slave->sii_product_code) { - 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_error; - return; - } - - // have all states been validated? - if (slave->list.next == &fsm->master->slaves) { - fsm->slave = list_entry(fsm->master->slaves.next, ec_slave_t, list); - // start writing addresses to offline slaves - ec_fsm_master_action_addresses(fsm); - return; - } - - // validate next slave - fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list); - fsm->master_state = ec_fsm_master_validate_vendor; - ec_fsm_sii_read(&fsm->fsm_sii, slave, 0x0008, EC_FSM_SII_POSITION); - ec_fsm_sii_exec(&fsm->fsm_sii); // execute immediately -} - -/*****************************************************************************/ - -/** - Master state: REWRITE ADDRESS. - Checks, if the new station address has been written to the slave. -*/ - -void ec_fsm_master_rewrite_addresses(ec_fsm_t *fsm - /**< finite state machine */ - ) -{ - ec_slave_t *slave = fsm->slave; - ec_datagram_t *datagram = &fsm->datagram; - - if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) { - ec_master_queue_datagram(fsm->master, &fsm->datagram); - return; - } - - if (datagram->state != EC_DATAGRAM_RECEIVED) { - EC_ERR("Failed to receive address datagram for slave %i.\n", - slave->ring_position); - fsm->master_state = ec_fsm_master_error; - return; - } - - if (datagram->working_counter != 1) { - EC_ERR("Failed to write station address - slave %i did not respond.\n", - slave->ring_position); - fsm->master_state = ec_fsm_master_error; - return; - } - - if (fsm->slave->list.next == &fsm->master->slaves) { // last slave? - fsm->master_state = ec_fsm_master_start; - fsm->master_state(fsm); // execute immediately - return; - } - - // check next slave - fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list); - // Write new station address to slave - ec_fsm_master_action_addresses(fsm); -} - -/*****************************************************************************/ - -/** - Master state: SCAN SLAVES. - Executes the sub-statemachine for the scanning of a slave. -*/ - -void ec_fsm_master_scan_slaves(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_slave_state_end - && fsm->slave_state != ec_fsm_slave_state_error) return; - - // another slave to fetch? - 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); - - // set initial states of all slaves to PREOP to make mailbox - // communication possible - list_for_each_entry(slave, &master->slaves, list) { - ec_slave_request_state(slave, EC_SLAVE_STATE_PREOP); - } - - fsm->master_state = ec_fsm_master_end; -} - -/*****************************************************************************/ - -/** - Master state: CONFIGURE SLAVES. - Starts configuring a slave. -*/ - -void ec_fsm_master_configure_slave(ec_fsm_t *fsm - /**< finite state machine */ - ) -{ - fsm->slave_state(fsm); // execute slave's state machine - - if (fsm->slave_state != ec_fsm_slave_state_end - && fsm->slave_state != ec_fsm_slave_state_error) return; - - ec_fsm_master_action_process_states(fsm); -} - -/*****************************************************************************/ - -/** - Master state: WRITE EEPROM. -*/ - -void ec_fsm_master_write_eeprom(ec_fsm_t *fsm /**< finite state machine */) -{ - ec_slave_t *slave = fsm->slave; - - if (ec_fsm_sii_exec(&fsm->fsm_sii)) return; - - if (!ec_fsm_sii_success(&fsm->fsm_sii)) { - fsm->slave->error_flag = 1; - EC_ERR("Failed to write EEPROM contents to slave %i.\n", - slave->ring_position); - kfree(slave->new_eeprom_data); - slave->new_eeprom_data = NULL; - fsm->master_state = ec_fsm_master_error; - return; - } - - fsm->sii_offset++; - if (fsm->sii_offset < slave->new_eeprom_size) { - ec_fsm_sii_write(&fsm->fsm_sii, slave, fsm->sii_offset, - slave->new_eeprom_data + fsm->sii_offset, - EC_FSM_SII_NODE); - ec_fsm_sii_exec(&fsm->fsm_sii); // execute immediately - return; - } - - // finished writing EEPROM - EC_INFO("Finished writing EEPROM of slave %i.\n", slave->ring_position); - kfree(slave->new_eeprom_data); - slave->new_eeprom_data = NULL; - - // TODO: Evaluate new EEPROM contents! - - // restart master state machine. - fsm->master_state = ec_fsm_master_start; - fsm->master_state(fsm); // execute immediately -} - -/*****************************************************************************/ - -/** - Master state: SDODICT. -*/ - -void ec_fsm_master_sdodict(ec_fsm_t *fsm /**< finite state machine */) -{ - ec_slave_t *slave = fsm->slave; - ec_master_t *master = fsm->master; - - if (ec_fsm_coe_exec(&fsm->fsm_coe)) return; - - if (!ec_fsm_coe_success(&fsm->fsm_coe)) { - fsm->master_state = ec_fsm_master_error; - return; - } - - // SDO dictionary fetching finished - - if (master->debug_level) { - unsigned int sdo_count, entry_count; - ec_slave_sdo_dict_info(slave, &sdo_count, &entry_count); - EC_DBG("Fetched %i SDOs and %i entries from slave %i.\n", - sdo_count, entry_count, slave->ring_position); - } - - // restart master state machine. - fsm->master_state = ec_fsm_master_start; - fsm->master_state(fsm); // execute immediately -} - -/*****************************************************************************/ - -/** - Master state: SDO REQUEST. -*/ - -void ec_fsm_master_sdo_request(ec_fsm_t *fsm /**< finite state machine */) -{ - ec_master_t *master = fsm->master; - ec_sdo_request_t *request = fsm->sdo_request; - - if (ec_fsm_coe_exec(&fsm->fsm_coe)) return; - - if (!ec_fsm_coe_success(&fsm->fsm_coe)) { - request->return_code = -1; - master->sdo_seq_master++; - fsm->master_state = ec_fsm_master_error; - return; - } - - // SDO dictionary fetching finished - - request->return_code = 1; - master->sdo_seq_master++; - - // restart master state machine. - fsm->master_state = ec_fsm_master_start; - 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 - *****************************************************************************/ - -/** - Slave scan state: START. - First state of the slave state machine. Writes the station address to the - slave, according to its ring position. -*/ - -void ec_fsm_slavescan_start(ec_fsm_t *fsm /**< finite state machine */) -{ - ec_datagram_t *datagram = &fsm->datagram; - - // write station address - ec_datagram_apwr(datagram, fsm->slave->ring_position, 0x0010, 2); - EC_WRITE_U16(datagram->data, fsm->slave->station_address); - ec_master_queue_datagram(fsm->master, datagram); - fsm->retries = EC_FSM_RETRIES; - fsm->slave_state = ec_fsm_slavescan_address; -} - -/*****************************************************************************/ - -/** - Slave scan state: ADDRESS. -*/ - -void ec_fsm_slavescan_address(ec_fsm_t *fsm /**< finite state machine */) -{ - ec_datagram_t *datagram = &fsm->datagram; - - if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) { - ec_master_queue_datagram(fsm->master, &fsm->datagram); - return; - } - - if (datagram->state != EC_DATAGRAM_RECEIVED) { - fsm->slave_state = ec_fsm_slave_state_error; - EC_ERR("Failed to receive station address datagram for slave %i.\n", - fsm->slave->ring_position); - return; - } - - if (datagram->working_counter != 1) { - fsm->slave->error_flag = 1; - fsm->slave_state = ec_fsm_slave_state_error; - EC_ERR("Failed to write station address - slave %i did not respond.\n", - fsm->slave->ring_position); - return; - } - - // Read AL state - ec_datagram_nprd(datagram, fsm->slave->station_address, 0x0130, 2); - ec_master_queue_datagram(fsm->master, datagram); - fsm->retries = EC_FSM_RETRIES; - fsm->slave_state = ec_fsm_slavescan_state; -} - -/*****************************************************************************/ - -/** - Slave scan state: STATE. -*/ - -void ec_fsm_slavescan_state(ec_fsm_t *fsm /**< finite state machine */) -{ - ec_datagram_t *datagram = &fsm->datagram; - ec_slave_t *slave = fsm->slave; - - if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) { - ec_master_queue_datagram(fsm->master, datagram); - return; - } - - if (datagram->state != EC_DATAGRAM_RECEIVED) { - fsm->slave_state = ec_fsm_slave_state_error; - EC_ERR("Failed to receive AL state datagram from slave %i.\n", - fsm->slave->ring_position); - return; - } - - if (datagram->working_counter != 1) { - fsm->slave->error_flag = 1; - fsm->slave_state = ec_fsm_slave_state_error; - EC_ERR("Failed to read AL state - slave %i did not respond.\n", - fsm->slave->ring_position); - return; - } - - slave->current_state = EC_READ_U8(datagram->data); - if (slave->current_state & EC_SLAVE_STATE_ACK_ERR) { - char state_str[EC_STATE_STRING_SIZE]; - ec_state_string(slave->current_state, state_str); - EC_WARN("Slave %i has state error bit set (%s)!\n", - slave->ring_position, state_str); - } - - // read base data - ec_datagram_nprd(datagram, fsm->slave->station_address, 0x0000, 6); - ec_master_queue_datagram(fsm->master, datagram); - fsm->retries = EC_FSM_RETRIES; - fsm->slave_state = ec_fsm_slavescan_base; -} - -/*****************************************************************************/ - -/** - Slave scan state: BASE. -*/ - -void ec_fsm_slavescan_base(ec_fsm_t *fsm /**< finite state machine */) -{ - ec_datagram_t *datagram = &fsm->datagram; - ec_slave_t *slave = fsm->slave; - - if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) { - ec_master_queue_datagram(fsm->master, datagram); - return; - } - - if (datagram->state != EC_DATAGRAM_RECEIVED) { - fsm->slave_state = ec_fsm_slave_state_error; - EC_ERR("Failed to receive base data datagram for slave %i.\n", - slave->ring_position); - return; - } - - if (datagram->working_counter != 1) { - fsm->slave->error_flag = 1; - fsm->slave_state = ec_fsm_slave_state_error; - EC_ERR("Failed to read base data - slave %i did not respond.\n", - slave->ring_position); - return; - } - - slave->base_type = EC_READ_U8 (datagram->data); - slave->base_revision = EC_READ_U8 (datagram->data + 1); - slave->base_build = EC_READ_U16(datagram->data + 2); - slave->base_fmmu_count = EC_READ_U8 (datagram->data + 4); - slave->base_sync_count = EC_READ_U8 (datagram->data + 5); - - if (slave->base_fmmu_count > EC_MAX_FMMUS) - slave->base_fmmu_count = EC_MAX_FMMUS; - - // read data link status - ec_datagram_nprd(datagram, slave->station_address, 0x0110, 2); - ec_master_queue_datagram(slave->master, datagram); - fsm->retries = EC_FSM_RETRIES; - fsm->slave_state = ec_fsm_slavescan_datalink; -} - -/*****************************************************************************/ - -/** - Slave scan state: DATALINK. -*/ - -void ec_fsm_slavescan_datalink(ec_fsm_t *fsm /**< finite state machine */) -{ - ec_datagram_t *datagram = &fsm->datagram; - ec_slave_t *slave = fsm->slave; - uint16_t dl_status; - unsigned int i; - - if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) { - ec_master_queue_datagram(fsm->master, datagram); - return; - } - - if (datagram->state != EC_DATAGRAM_RECEIVED) { - fsm->slave_state = ec_fsm_slave_state_error; - EC_ERR("Failed to receive DL status datagram from slave %i.\n", - slave->ring_position); - return; - } - - if (datagram->working_counter != 1) { - fsm->slave->error_flag = 1; - fsm->slave_state = ec_fsm_slave_state_error; - EC_ERR("Failed to read DL status - slave %i did not respond.\n", - slave->ring_position); - return; - } - - dl_status = EC_READ_U16(datagram->data); - for (i = 0; i < 4; i++) { - slave->dl_link[i] = dl_status & (1 << (4 + i)) ? 1 : 0; - slave->dl_loop[i] = dl_status & (1 << (8 + i * 2)) ? 1 : 0; - slave->dl_signal[i] = dl_status & (1 << (9 + i * 2)) ? 1 : 0; - } - - // Start fetching EEPROM size - - fsm->sii_offset = 0x0040; // first category header - ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset, EC_FSM_SII_NODE); - fsm->slave_state = ec_fsm_slavescan_eeprom_size; - fsm->slave_state(fsm); // execute state immediately -} - -/*****************************************************************************/ - -/** - Slave scan state: EEPROM SIZE. -*/ - -void ec_fsm_slavescan_eeprom_size(ec_fsm_t *fsm /**< finite state machine */) -{ - ec_slave_t *slave = fsm->slave; - uint16_t cat_type, cat_size; - - if (ec_fsm_sii_exec(&fsm->fsm_sii)) return; - - if (!ec_fsm_sii_success(&fsm->fsm_sii)) { - fsm->slave->error_flag = 1; - fsm->slave_state = ec_fsm_slave_state_error; - EC_ERR("Failed to read EEPROM size of slave %i.\n", - slave->ring_position); - return; - } - - cat_type = EC_READ_U16(fsm->fsm_sii.value); - cat_size = EC_READ_U16(fsm->fsm_sii.value + 2); - - if (cat_type != 0xFFFF) { // not the last category - fsm->sii_offset += cat_size + 2; - ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset, - EC_FSM_SII_NODE); - ec_fsm_sii_exec(&fsm->fsm_sii); // execute state immediately - return; - } - - slave->eeprom_size = (fsm->sii_offset + 1) * 2; - - if (slave->eeprom_data) { - EC_INFO("Freeing old EEPROM data on slave %i...\n", - slave->ring_position); - kfree(slave->eeprom_data); - } - - if (!(slave->eeprom_data = - (uint8_t *) kmalloc(slave->eeprom_size, GFP_ATOMIC))) { - fsm->slave->error_flag = 1; - fsm->slave_state = ec_fsm_slave_state_error; - EC_ERR("Failed to allocate EEPROM data on slave %i.\n", - slave->ring_position); - return; - } - - // Start fetching EEPROM contents - - fsm->slave_state = ec_fsm_slavescan_eeprom_data; - fsm->sii_offset = 0x0000; - ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset, EC_FSM_SII_NODE); - ec_fsm_sii_exec(&fsm->fsm_sii); // execute state immediately -} - -/*****************************************************************************/ - -/** - Slave scan state: EEPROM DATA. -*/ - -void ec_fsm_slavescan_eeprom_data(ec_fsm_t *fsm /**< finite state machine */) -{ - ec_slave_t *slave = fsm->slave; - uint16_t *cat_word, cat_type, cat_size; - - if (ec_fsm_sii_exec(&fsm->fsm_sii)) return; - - if (!ec_fsm_sii_success(&fsm->fsm_sii)) { - fsm->slave->error_flag = 1; - fsm->slave_state = ec_fsm_slave_state_error; - EC_ERR("Failed to fetch EEPROM contents of slave %i.\n", - slave->ring_position); - return; - } - - // 2 words fetched - - if (fsm->sii_offset + 2 <= slave->eeprom_size / 2) { // 2 words fit - memcpy(slave->eeprom_data + fsm->sii_offset * 2, - fsm->fsm_sii.value, 4); - } - else { // copy the last word - memcpy(slave->eeprom_data + fsm->sii_offset * 2, - fsm->fsm_sii.value, 2); - } - - if (fsm->sii_offset + 2 < slave->eeprom_size / 2) { - // fetch the next 2 words - fsm->sii_offset += 2; - ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset, - EC_FSM_SII_NODE); - ec_fsm_sii_exec(&fsm->fsm_sii); // execute state immediately - return; - } - - // Evaluate EEPROM contents - - slave->sii_alias = - EC_READ_U16(slave->eeprom_data + 2 * 0x0004); - slave->sii_vendor_id = - EC_READ_U32(slave->eeprom_data + 2 * 0x0008); - slave->sii_product_code = - EC_READ_U32(slave->eeprom_data + 2 * 0x000A); - slave->sii_revision_number = - EC_READ_U32(slave->eeprom_data + 2 * 0x000C); - slave->sii_serial_number = - EC_READ_U32(slave->eeprom_data + 2 * 0x000E); - slave->sii_rx_mailbox_offset = - EC_READ_U16(slave->eeprom_data + 2 * 0x0018); - slave->sii_rx_mailbox_size = - EC_READ_U16(slave->eeprom_data + 2 * 0x0019); - slave->sii_tx_mailbox_offset = - EC_READ_U16(slave->eeprom_data + 2 * 0x001A); - slave->sii_tx_mailbox_size = - EC_READ_U16(slave->eeprom_data + 2 * 0x001B); - slave->sii_mailbox_protocols = - EC_READ_U16(slave->eeprom_data + 2 * 0x001C); - - // evaluate category data - cat_word = (uint16_t *) slave->eeprom_data + 0x0040; - while (EC_READ_U16(cat_word) != 0xFFFF) { - cat_type = EC_READ_U16(cat_word) & 0x7FFF; - cat_size = EC_READ_U16(cat_word + 1); - - switch (cat_type) { - case 0x000A: - if (ec_slave_fetch_strings(slave, (uint8_t *) (cat_word + 2))) - goto end; - break; - case 0x001E: - ec_slave_fetch_general(slave, (uint8_t *) (cat_word + 2)); - break; - case 0x0028: - break; - case 0x0029: - if (ec_slave_fetch_sync(slave, (uint8_t *) (cat_word + 2), - cat_size)) - goto end; - break; - case 0x0032: - if (ec_slave_fetch_pdo(slave, (uint8_t *) (cat_word + 2), - cat_size, EC_TX_PDO)) - goto end; - break; - case 0x0033: - if (ec_slave_fetch_pdo(slave, (uint8_t *) (cat_word + 2), - cat_size, EC_RX_PDO)) - goto end; - break; - default: - if (fsm->master->debug_level) - EC_WARN("Unknown category type 0x%04X in slave %i.\n", - cat_type, slave->ring_position); - } - - cat_word += cat_size + 2; - } - - fsm->slave_state = ec_fsm_slave_state_end; - return; - -end: - EC_ERR("Failed to analyze category data.\n"); - fsm->slave->error_flag = 1; - fsm->slave_state = ec_fsm_slave_state_error; -} - -/****************************************************************************** - * slave configuration state machine - *****************************************************************************/ - -/** - Slave configuration state: START. -*/ - -void ec_fsm_slaveconf_state_start(ec_fsm_t *fsm /**< finite state machine */) -{ - if (fsm->master->debug_level) { - EC_DBG("Configuring slave %i...\n", fsm->slave->ring_position); - } - - ec_fsm_change_start(&fsm->fsm_change, fsm->slave, EC_SLAVE_STATE_INIT); - ec_fsm_change_exec(&fsm->fsm_change); - fsm->slave_state = ec_fsm_slaveconf_state_init; -} - -/*****************************************************************************/ - -/** - Slave configuration state: INIT. -*/ - -void ec_fsm_slaveconf_state_init(ec_fsm_t *fsm /**< finite state machine */) -{ - ec_master_t *master = fsm->master; - ec_slave_t *slave = fsm->slave; - ec_datagram_t *datagram = &fsm->datagram; - - if (ec_fsm_change_exec(&fsm->fsm_change)) return; - - if (!ec_fsm_change_success(&fsm->fsm_change)) { - slave->error_flag = 1; - fsm->slave_state = ec_fsm_slave_state_error; - return; - } - - slave->self_configured = 1; - - if (master->debug_level) { - EC_DBG("Slave %i is now in INIT.\n", slave->ring_position); - } - - // check and reset CRC fault counters - //ec_slave_check_crc(slave); - // TODO: Implement state machine for CRC checking. - - if (!slave->base_fmmu_count) { // skip FMMU configuration - ec_fsm_slaveconf_enter_sync(fsm); - return; - } - - if (master->debug_level) - EC_DBG("Clearing FMMU configurations of slave %i...\n", - slave->ring_position); - - // clear FMMU configurations - ec_datagram_npwr(datagram, slave->station_address, - 0x0600, EC_FMMU_SIZE * slave->base_fmmu_count); - memset(datagram->data, 0x00, EC_FMMU_SIZE * slave->base_fmmu_count); - ec_master_queue_datagram(master, datagram); - fsm->retries = EC_FSM_RETRIES; - fsm->slave_state = ec_fsm_slaveconf_state_clear_fmmus; -} - -/*****************************************************************************/ - -/** - Slave configuration state: CLEAR FMMU. -*/ - -void ec_fsm_slaveconf_state_clear_fmmus(ec_fsm_t *fsm - /**< finite state machine */) -{ - ec_datagram_t *datagram = &fsm->datagram; - - if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) { - ec_master_queue_datagram(fsm->master, datagram); - return; - } - - if (datagram->state != EC_DATAGRAM_RECEIVED) { - fsm->slave_state = ec_fsm_slave_state_error; - EC_ERR("Failed receive FMMU clearing datagram for slave %i.\n", - fsm->slave->ring_position); - return; - } - - if (datagram->working_counter != 1) { - fsm->slave->error_flag = 1; - fsm->slave_state = ec_fsm_slave_state_error; - EC_ERR("Failed to clear FMMUs - slave %i did not respond.\n", - fsm->slave->ring_position); - return; - } - - ec_fsm_slaveconf_enter_sync(fsm); -} - -/*****************************************************************************/ - -/** -*/ - -void ec_fsm_slaveconf_enter_sync(ec_fsm_t *fsm /**< finite state machine */) -{ - ec_master_t *master = fsm->master; - ec_slave_t *slave = fsm->slave; - ec_datagram_t *datagram = &fsm->datagram; - const ec_sii_sync_t *sync; - ec_sii_sync_t mbox_sync; - - // slave is now in INIT - if (slave->current_state == slave->requested_state) { - fsm->slave_state = ec_fsm_slave_state_end; // successful - if (master->debug_level) { - EC_DBG("Finished configuration of slave %i.\n", - slave->ring_position); - } - return; - } - - if (!slave->base_sync_count) { // no sync managers - ec_fsm_slaveconf_enter_preop(fsm); - return; - } - - if (master->debug_level) { - EC_DBG("Configuring sync managers of slave %i.\n", - slave->ring_position); - } - - // configure sync managers - ec_datagram_npwr(datagram, slave->station_address, 0x0800, - EC_SYNC_SIZE * slave->base_sync_count); - memset(datagram->data, 0x00, EC_SYNC_SIZE * slave->base_sync_count); - - if (list_empty(&slave->sii_syncs)) { - if (slave->sii_rx_mailbox_offset && slave->sii_tx_mailbox_offset) { - if (slave->master->debug_level) - EC_DBG("Guessing sync manager settings for slave %i.\n", - slave->ring_position); - mbox_sync.index = 0; - mbox_sync.physical_start_address = slave->sii_tx_mailbox_offset; - mbox_sync.length = slave->sii_tx_mailbox_size; - mbox_sync.control_register = 0x26; - mbox_sync.enable = 0x01; - mbox_sync.est_length = 0; - ec_sync_config(&mbox_sync, slave, - datagram->data + EC_SYNC_SIZE * mbox_sync.index); - mbox_sync.index = 1; - mbox_sync.physical_start_address = slave->sii_rx_mailbox_offset; - mbox_sync.length = slave->sii_rx_mailbox_size; - mbox_sync.control_register = 0x22; - mbox_sync.enable = 0x01; - mbox_sync.est_length = 0; - ec_sync_config(&mbox_sync, slave, - datagram->data + EC_SYNC_SIZE * mbox_sync.index); - } - } - else if (slave->sii_mailbox_protocols) { // mailboxes present - list_for_each_entry(sync, &slave->sii_syncs, list) { - // only configure mailbox sync-managers - if (sync->index != 0 && sync->index != 1) continue; - ec_sync_config(sync, slave, - datagram->data + EC_SYNC_SIZE * sync->index); - } - } - - ec_master_queue_datagram(fsm->master, datagram); - fsm->retries = EC_FSM_RETRIES; - fsm->slave_state = ec_fsm_slaveconf_state_sync; -} - -/*****************************************************************************/ - -/** - Slave configuration state: SYNC. -*/ - -void ec_fsm_slaveconf_state_sync(ec_fsm_t *fsm /**< finite state machine */) -{ - ec_datagram_t *datagram = &fsm->datagram; - ec_slave_t *slave = fsm->slave; - - if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) { - ec_master_queue_datagram(fsm->master, datagram); - return; - } - - if (datagram->state != EC_DATAGRAM_RECEIVED) { - fsm->slave_state = ec_fsm_slave_state_error; - EC_ERR("Failed to receive sync manager configuration datagram for" - " slave %i.\n", slave->ring_position); - return; - } - - if (datagram->working_counter != 1) { - slave->error_flag = 1; - fsm->slave_state = ec_fsm_slave_state_error; - EC_ERR("Failed to set sync managers - slave %i did not respond.\n", - slave->ring_position); - return; - } - - ec_fsm_slaveconf_enter_preop(fsm); -} - -/*****************************************************************************/ - -/** - */ - -void ec_fsm_slaveconf_enter_preop(ec_fsm_t *fsm /**< finite state machine */) -{ - fsm->slave_state = ec_fsm_slaveconf_state_preop; - ec_fsm_change_start(&fsm->fsm_change, fsm->slave, EC_SLAVE_STATE_PREOP); - ec_fsm_change_exec(&fsm->fsm_change); // execute immediately -} - -/*****************************************************************************/ - -/** - Slave configuration state: PREOP. -*/ - -void ec_fsm_slaveconf_state_preop(ec_fsm_t *fsm /**< finite state machine */) -{ - ec_slave_t *slave = fsm->slave; - ec_master_t *master = fsm->master; - - if (ec_fsm_change_exec(&fsm->fsm_change)) return; - - if (!ec_fsm_change_success(&fsm->fsm_change)) { - slave->error_flag = 1; - fsm->slave_state = ec_fsm_slave_state_error; - return; - } - - // slave is now in PREOP - slave->jiffies_preop = fsm->datagram.jiffies_received; - - if (master->debug_level) { - EC_DBG("Slave %i is now in PREOP.\n", slave->ring_position); - } - - if (slave->current_state == slave->requested_state) { - fsm->slave_state = ec_fsm_slave_state_end; // successful - if (master->debug_level) { - EC_DBG("Finished configuration of slave %i.\n", - slave->ring_position); - } - return; - } - - ec_fsm_slaveconf_enter_sync2(fsm); -} - -/*****************************************************************************/ - -/** -*/ - -void ec_fsm_slaveconf_enter_sync2(ec_fsm_t *fsm /**< finite state machine */) -{ - ec_slave_t *slave = fsm->slave; - ec_datagram_t *datagram = &fsm->datagram; - ec_sii_sync_t *sync; - - if (list_empty(&slave->sii_syncs)) { - ec_fsm_slaveconf_enter_fmmu(fsm); - return; - } - - // configure sync managers for process data - ec_datagram_npwr(datagram, slave->station_address, 0x0800, - EC_SYNC_SIZE * slave->base_sync_count); - memset(datagram->data, 0x00, EC_SYNC_SIZE * slave->base_sync_count); - - list_for_each_entry(sync, &slave->sii_syncs, list) { - ec_sync_config(sync, slave, - datagram->data + EC_SYNC_SIZE * sync->index); - } - - ec_master_queue_datagram(fsm->master, datagram); - fsm->retries = EC_FSM_RETRIES; - fsm->slave_state = ec_fsm_slaveconf_state_sync2; -} - -/*****************************************************************************/ - -/** - Slave configuration state: SYNC2. -*/ - -void ec_fsm_slaveconf_state_sync2(ec_fsm_t *fsm /**< finite state machine */) -{ - ec_datagram_t *datagram = &fsm->datagram; - ec_slave_t *slave = fsm->slave; - - if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) { - ec_master_queue_datagram(fsm->master, datagram); - return; - } - - if (datagram->state != EC_DATAGRAM_RECEIVED) { - fsm->slave_state = ec_fsm_slave_state_error; - EC_ERR("Failed to receive process data sync manager configuration" - " datagram for slave %i.\n", - slave->ring_position); - return; - } - - if (datagram->working_counter != 1) { - slave->error_flag = 1; - fsm->slave_state = ec_fsm_slave_state_error; - EC_ERR("Failed to set process data sync managers - slave %i did not" - " respond.\n", slave->ring_position); - return; - } - - ec_fsm_slaveconf_enter_fmmu(fsm); -} - -/*****************************************************************************/ - -/** -*/ - -void ec_fsm_slaveconf_enter_fmmu(ec_fsm_t *fsm /**< finite state machine */) -{ - ec_slave_t *slave = fsm->slave; - ec_master_t *master = slave->master; - ec_datagram_t *datagram = &fsm->datagram; - unsigned int j; - - if (!slave->base_fmmu_count) { // skip FMMU configuration - ec_fsm_slaveconf_enter_sdoconf(fsm); - return; - } - - // configure FMMUs - ec_datagram_npwr(datagram, slave->station_address, - 0x0600, EC_FMMU_SIZE * slave->base_fmmu_count); - memset(datagram->data, 0x00, EC_FMMU_SIZE * slave->base_fmmu_count); - for (j = 0; j < slave->fmmu_count; j++) { - ec_fmmu_config(&slave->fmmus[j], slave, - datagram->data + EC_FMMU_SIZE * j); - } - - ec_master_queue_datagram(master, datagram); - fsm->retries = EC_FSM_RETRIES; - fsm->slave_state = ec_fsm_slaveconf_state_fmmu; -} - -/*****************************************************************************/ - -/** - Slave configuration state: FMMU. -*/ - -void ec_fsm_slaveconf_state_fmmu(ec_fsm_t *fsm /**< finite state machine */) -{ - ec_datagram_t *datagram = &fsm->datagram; - ec_slave_t *slave = fsm->slave; - - if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) { - ec_master_queue_datagram(fsm->master, datagram); - return; - } - - if (datagram->state != EC_DATAGRAM_RECEIVED) { - fsm->slave_state = ec_fsm_slave_state_error; - EC_ERR("Failed to receive FMMUs datagram for slave %i.\n", - fsm->slave->ring_position); - return; - } - - if (datagram->working_counter != 1) { - fsm->slave->error_flag = 1; - fsm->slave_state = ec_fsm_slave_state_error; - EC_ERR("Failed to set FMMUs - slave %i did not respond.\n", - fsm->slave->ring_position); - return; - } - - // No CoE configuration to be applied? Jump to SAVEOP state. - if (list_empty(&slave->sdo_confs)) { // skip SDO configuration - ec_fsm_slaveconf_enter_saveop(fsm); - return; - } - - ec_fsm_slaveconf_enter_sdoconf(fsm); -} - -/*****************************************************************************/ - -/** - */ - -void ec_fsm_slaveconf_enter_sdoconf(ec_fsm_t *fsm /**< finite state machine */) -{ - ec_slave_t *slave = fsm->slave; - - if (list_empty(&slave->sdo_confs)) { // skip SDO configuration - ec_fsm_slaveconf_enter_saveop(fsm); - return; - } - - // start SDO configuration - fsm->slave_state = ec_fsm_slaveconf_state_sdoconf; - fsm->sdodata = list_entry(fsm->slave->sdo_confs.next, ec_sdo_data_t, list); - ec_fsm_coe_download(&fsm->fsm_coe, fsm->slave, fsm->sdodata); - ec_fsm_coe_exec(&fsm->fsm_coe); // execute immediately -} - -/*****************************************************************************/ - -/** - Slave configuration state: SDOCONF. -*/ - -void ec_fsm_slaveconf_state_sdoconf(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->slave->error_flag = 1; - fsm->slave_state = ec_fsm_slave_state_error; - return; - } - - // Another SDO to configure? - if (fsm->sdodata->list.next != &fsm->slave->sdo_confs) { - fsm->sdodata = list_entry(fsm->sdodata->list.next, - ec_sdo_data_t, list); - ec_fsm_coe_download(&fsm->fsm_coe, fsm->slave, fsm->sdodata); - ec_fsm_coe_exec(&fsm->fsm_coe); // execute immediately - return; - } - - // All SDOs are now configured. - - // set state to SAVEOP - ec_fsm_slaveconf_enter_saveop(fsm); -} - -/*****************************************************************************/ - -/** - */ - -void ec_fsm_slaveconf_enter_saveop(ec_fsm_t *fsm /**< finite state machine */) -{ - fsm->slave_state = ec_fsm_slaveconf_state_saveop; - ec_fsm_change_start(&fsm->fsm_change, fsm->slave, EC_SLAVE_STATE_SAVEOP); - ec_fsm_change_exec(&fsm->fsm_change); // execute immediately -} - -/*****************************************************************************/ - -/** - Slave configuration state: SAVEOP. -*/ - -void ec_fsm_slaveconf_state_saveop(ec_fsm_t *fsm /**< finite state machine */) -{ - ec_master_t *master = fsm->master; - ec_slave_t *slave = fsm->slave; - - if (ec_fsm_change_exec(&fsm->fsm_change)) return; - - if (!ec_fsm_change_success(&fsm->fsm_change)) { - fsm->slave->error_flag = 1; - fsm->slave_state = ec_fsm_slave_state_error; - return; - } - - // slave is now in SAVEOP - - if (master->debug_level) { - EC_DBG("Slave %i is now in SAVEOP.\n", slave->ring_position); - } - - if (fsm->slave->current_state == fsm->slave->requested_state) { - fsm->slave_state = ec_fsm_slave_state_end; // successful - if (master->debug_level) { - EC_DBG("Finished configuration of slave %i.\n", - slave->ring_position); - } - return; - } - - // set state to OP - fsm->slave_state = ec_fsm_slaveconf_state_op; - ec_fsm_change_start(&fsm->fsm_change, slave, EC_SLAVE_STATE_OP); - ec_fsm_change_exec(&fsm->fsm_change); // execute immediately -} - -/*****************************************************************************/ - -/** - Slave configuration state: OP -*/ - -void ec_fsm_slaveconf_state_op(ec_fsm_t *fsm /**< finite state machine */) -{ - ec_master_t *master = fsm->master; - ec_slave_t *slave = fsm->slave; - - if (ec_fsm_change_exec(&fsm->fsm_change)) return; - - if (!ec_fsm_change_success(&fsm->fsm_change)) { - slave->error_flag = 1; - fsm->slave_state = ec_fsm_slave_state_error; - return; - } - - // slave is now in OP - - if (master->debug_level) { - EC_DBG("Slave %i is now in OP.\n", slave->ring_position); - EC_DBG("Finished configuration of slave %i.\n", slave->ring_position); - } - - fsm->slave_state = ec_fsm_slave_state_end; // successful -} - -/****************************************************************************** - * Common state functions - *****************************************************************************/ - -/** - State: ERROR. -*/ - -void ec_fsm_slave_state_error(ec_fsm_t *fsm /**< finite state machine */) -{ -} - -/*****************************************************************************/ - -/** - State: END. -*/ - -void ec_fsm_slave_state_end(ec_fsm_t *fsm /**< finite state machine */) -{ -} - -/*****************************************************************************/