fp@830: /****************************************************************************** fp@830: * fp@830: * $Id$ fp@830: * fp@830: * Copyright (C) 2006 Florian Pose, Ingenieurgemeinschaft IgH fp@830: * fp@830: * This file is part of the IgH EtherCAT Master. fp@830: * fp@830: * The IgH EtherCAT Master is free software; you can redistribute it fp@830: * and/or modify it under the terms of the GNU General Public License fp@830: * as published by the Free Software Foundation; either version 2 of the fp@830: * License, or (at your option) any later version. fp@830: * fp@830: * The IgH EtherCAT Master is distributed in the hope that it will be fp@830: * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of fp@830: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the fp@830: * GNU General Public License for more details. fp@830: * fp@830: * You should have received a copy of the GNU General Public License fp@830: * along with the IgH EtherCAT Master; if not, write to the Free Software fp@830: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA fp@830: * fp@830: * The right to use EtherCAT Technology is granted and comes free of fp@830: * charge under condition of compatibility of product made by fp@830: * Licensee. People intending to distribute/sell products based on the fp@830: * code, have to sign an agreement to guarantee that products using fp@830: * software based on IgH EtherCAT master stay compatible with the actual fp@830: * EtherCAT specification (which are released themselves as an open fp@830: * standard) as the (only) precondition to have the right to use EtherCAT fp@830: * Technology, IP and trade marks. fp@830: * fp@830: *****************************************************************************/ fp@830: fp@830: /** fp@830: \file fp@830: EtherCAT slave configuration state machine. fp@830: */ fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: #include "globals.h" fp@830: #include "master.h" fp@830: #include "mailbox.h" fp@830: #include "slave_config.h" fp@830: #include "fsm_slave_config.h" fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: void ec_fsm_slave_config_state_start(ec_fsm_slave_config_t *); fp@830: void ec_fsm_slave_config_state_init(ec_fsm_slave_config_t *); fp@830: void ec_fsm_slave_config_state_clear_fmmus(ec_fsm_slave_config_t *); fp@830: void ec_fsm_slave_config_state_mbox_sync(ec_fsm_slave_config_t *); fp@830: void ec_fsm_slave_config_state_preop(ec_fsm_slave_config_t *); fp@830: void ec_fsm_slave_config_state_sdo_conf(ec_fsm_slave_config_t *); fp@830: void ec_fsm_slave_config_state_mapping(ec_fsm_slave_config_t *); fp@830: void ec_fsm_slave_config_state_pdo_conf(ec_fsm_slave_config_t *); fp@830: void ec_fsm_slave_config_state_pdo_sync(ec_fsm_slave_config_t *); fp@830: void ec_fsm_slave_config_state_fmmu(ec_fsm_slave_config_t *); fp@830: void ec_fsm_slave_config_state_safeop(ec_fsm_slave_config_t *); fp@830: void ec_fsm_slave_config_state_op(ec_fsm_slave_config_t *); fp@830: fp@830: void ec_fsm_slave_config_enter_mbox_sync(ec_fsm_slave_config_t *); fp@830: void ec_fsm_slave_config_enter_preop(ec_fsm_slave_config_t *); fp@830: void ec_fsm_slave_config_enter_sdo_conf(ec_fsm_slave_config_t *); fp@830: void ec_fsm_slave_config_enter_mapping(ec_fsm_slave_config_t *); fp@830: void ec_fsm_slave_config_enter_pdo_sync(ec_fsm_slave_config_t *); fp@830: void ec_fsm_slave_config_enter_fmmu(ec_fsm_slave_config_t *); fp@830: void ec_fsm_slave_config_enter_safeop(ec_fsm_slave_config_t *); fp@830: fp@830: void ec_fsm_slave_config_state_end(ec_fsm_slave_config_t *); fp@830: void ec_fsm_slave_config_state_error(ec_fsm_slave_config_t *); fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** Constructor. fp@830: */ fp@830: void ec_fsm_slave_config_init(ec_fsm_slave_config_t *fsm, /**< slave state machine */ fp@830: ec_datagram_t *datagram /**< datagram structure to use */ fp@830: ) fp@830: { fp@830: fsm->datagram = datagram; fp@830: fp@830: // init sub state machines fp@830: ec_fsm_change_init(&fsm->fsm_change, fsm->datagram); fp@830: ec_fsm_coe_init(&fsm->fsm_coe, fsm->datagram); fp@830: ec_fsm_pdo_mapping_init(&fsm->fsm_pdo_map, &fsm->fsm_coe); fp@830: ec_fsm_pdo_config_init(&fsm->fsm_pdo_conf, &fsm->fsm_coe); fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** Destructor. fp@830: */ fp@830: void ec_fsm_slave_config_clear(ec_fsm_slave_config_t *fsm /**< slave state machine */) fp@830: { fp@830: // clear sub state machines fp@830: ec_fsm_change_clear(&fsm->fsm_change); fp@830: ec_fsm_coe_clear(&fsm->fsm_coe); fp@830: ec_fsm_pdo_mapping_clear(&fsm->fsm_pdo_map); fp@830: ec_fsm_pdo_config_clear(&fsm->fsm_pdo_conf); fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** fp@830: * Start slave configuration state machine. fp@830: */ fp@830: fp@830: void ec_fsm_slave_config_start(ec_fsm_slave_config_t *fsm, /**< slave state machine */ fp@830: ec_slave_t *slave /**< slave to configure */ fp@830: ) fp@830: { fp@830: fsm->slave = slave; fp@830: fsm->state = ec_fsm_slave_config_state_start; fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** fp@830: \return false, if state machine has terminated fp@830: */ fp@830: fp@830: int ec_fsm_slave_config_running(const ec_fsm_slave_config_t *fsm /**< slave state machine */) fp@830: { fp@830: return fsm->state != ec_fsm_slave_config_state_end fp@830: && fsm->state != ec_fsm_slave_config_state_error; fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** fp@830: Executes the current state of the state machine. fp@830: If the state machine's datagram is not sent or received yet, the execution fp@830: of the state machine is delayed to the next cycle. fp@830: \return false, if state machine has terminated fp@830: */ fp@830: fp@830: int ec_fsm_slave_config_exec(ec_fsm_slave_config_t *fsm /**< slave state machine */) fp@830: { fp@830: if (fsm->datagram->state == EC_DATAGRAM_SENT fp@830: || fsm->datagram->state == EC_DATAGRAM_QUEUED) { fp@830: // datagram was not sent or received yet. fp@830: return ec_fsm_slave_config_running(fsm); fp@830: } fp@830: fp@830: fsm->state(fsm); fp@830: return ec_fsm_slave_config_running(fsm); fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** fp@830: \return true, if the state machine terminated gracefully fp@830: */ fp@830: fp@830: int ec_fsm_slave_config_success(const ec_fsm_slave_config_t *fsm /**< slave state machine */) fp@830: { fp@830: return fsm->state == ec_fsm_slave_config_state_end; fp@830: } fp@830: fp@830: /****************************************************************************** fp@830: * Slave configuration state machine fp@830: *****************************************************************************/ fp@830: fp@830: /** fp@830: Slave configuration state: START. fp@830: */ fp@830: fp@830: void ec_fsm_slave_config_state_start(ec_fsm_slave_config_t *fsm /**< slave state machine */) fp@830: { fp@830: if (fsm->slave->master->debug_level) { fp@830: EC_DBG("Configuring slave %i...\n", fsm->slave->ring_position); fp@830: } fp@830: fp@830: ec_fsm_change_start(&fsm->fsm_change, fsm->slave, EC_SLAVE_STATE_INIT); fp@830: ec_fsm_change_exec(&fsm->fsm_change); fp@830: fsm->state = ec_fsm_slave_config_state_init; fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** fp@830: Slave configuration state: INIT. fp@830: */ fp@830: fp@830: void ec_fsm_slave_config_state_init(ec_fsm_slave_config_t *fsm /**< slave state machine */) fp@830: { fp@830: ec_master_t *master = fsm->slave->master; fp@830: ec_slave_t *slave = fsm->slave; fp@830: ec_datagram_t *datagram = fsm->datagram; fp@830: fp@830: if (ec_fsm_change_exec(&fsm->fsm_change)) return; fp@830: fp@830: if (!ec_fsm_change_success(&fsm->fsm_change)) { fp@830: if (!fsm->fsm_change.spontaneous_change) fp@830: slave->error_flag = 1; fp@830: fsm->state = ec_fsm_slave_config_state_error; fp@830: return; fp@830: } fp@830: fp@830: slave->self_configured = 1; fp@830: fp@830: if (master->debug_level) { fp@830: EC_DBG("Slave %i is now in INIT.\n", slave->ring_position); fp@830: } fp@830: fp@830: // check and reset CRC fault counters fp@830: //ec_slave_check_crc(slave); fp@830: // TODO: Implement state machine for CRC checking. fp@830: fp@830: if (!slave->base_fmmu_count) { // skip FMMU configuration fp@830: ec_fsm_slave_config_enter_mbox_sync(fsm); fp@830: return; fp@830: } fp@830: fp@830: if (master->debug_level) fp@830: EC_DBG("Clearing FMMU configurations of slave %i...\n", fp@830: slave->ring_position); fp@830: fp@830: // clear FMMU configurations fp@830: ec_datagram_fpwr(datagram, slave->station_address, fp@830: 0x0600, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count); fp@830: memset(datagram->data, 0x00, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count); fp@830: fsm->retries = EC_FSM_RETRIES; fp@830: fsm->state = ec_fsm_slave_config_state_clear_fmmus; fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** fp@830: Slave configuration state: CLEAR FMMU. fp@830: */ fp@830: fp@830: void ec_fsm_slave_config_state_clear_fmmus(ec_fsm_slave_config_t *fsm fp@830: /**< slave state machine */) fp@830: { fp@830: ec_datagram_t *datagram = fsm->datagram; fp@830: fp@830: if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) fp@830: return; fp@830: fp@830: if (datagram->state != EC_DATAGRAM_RECEIVED) { fp@830: fsm->state = ec_fsm_slave_config_state_error; fp@830: EC_ERR("Failed receive FMMU clearing datagram for slave %i.\n", fp@830: fsm->slave->ring_position); fp@830: return; fp@830: } fp@830: fp@830: if (datagram->working_counter != 1) { fp@830: fsm->slave->error_flag = 1; fp@830: fsm->state = ec_fsm_slave_config_state_error; fp@830: EC_ERR("Failed to clear FMMUs of slave %i: ", fp@830: fsm->slave->ring_position); fp@830: ec_datagram_print_wc_error(datagram); fp@830: return; fp@830: } fp@830: fp@830: ec_fsm_slave_config_enter_mbox_sync(fsm); fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** fp@830: * Check for mailbox sync managers to be configured. fp@830: */ fp@830: fp@830: void ec_fsm_slave_config_enter_mbox_sync( fp@830: ec_fsm_slave_config_t *fsm /**< slave state machine */ fp@830: ) fp@830: { fp@830: ec_master_t *master = fsm->slave->master; fp@830: ec_slave_t *slave = fsm->slave; fp@830: ec_datagram_t *datagram = fsm->datagram; fp@830: unsigned int i; fp@830: fp@830: // slave is now in INIT fp@830: if (slave->current_state == slave->requested_state) { fp@830: fsm->state = ec_fsm_slave_config_state_end; // successful fp@830: if (master->debug_level) { fp@830: EC_DBG("Finished configuration of slave %i.\n", fp@830: slave->ring_position); fp@830: } fp@830: return; fp@830: } fp@830: fp@830: if (!slave->sii_mailbox_protocols) { fp@830: // no mailbox protocols supported fp@830: if (master->debug_level) fp@830: EC_DBG("Slave %u does not support mailbox communication.\n", fp@830: slave->ring_position); fp@830: ec_fsm_slave_config_enter_preop(fsm); fp@830: return; fp@830: } fp@830: fp@830: if (master->debug_level) { fp@830: EC_DBG("Configuring mailbox sync managers of slave %i.\n", fp@830: slave->ring_position); fp@830: } fp@830: fp@830: if (slave->sii_sync_count >= 2) { // mailbox configuration provided fp@830: ec_datagram_fpwr(datagram, slave->station_address, 0x0800, fp@830: EC_SYNC_PAGE_SIZE * slave->sii_sync_count); fp@830: memset(datagram->data, 0x00, fp@830: EC_SYNC_PAGE_SIZE * slave->sii_sync_count); fp@830: fp@830: for (i = 0; i < 2; i++) { fp@830: ec_sync_config(&slave->sii_syncs[i], slave->sii_syncs[i].length, fp@830: datagram->data + EC_SYNC_PAGE_SIZE * i); fp@830: } fp@830: } else { // no mailbox sync manager configurations provided fp@830: ec_sync_t sync; fp@830: fp@830: if (master->debug_level) fp@830: EC_DBG("Slave %u does not provide" fp@830: " mailbox sync manager configurations.\n", fp@830: slave->ring_position); fp@830: fp@830: ec_datagram_fpwr(datagram, slave->station_address, 0x0800, fp@830: EC_SYNC_PAGE_SIZE * 2); fp@830: memset(datagram->data, 0x00, EC_SYNC_PAGE_SIZE * 2); fp@830: fp@830: ec_sync_init(&sync, slave, 0); fp@830: sync.physical_start_address = slave->sii_rx_mailbox_offset; fp@830: sync.control_register = 0x26; fp@830: sync.enable = 1; fp@830: ec_sync_config(&sync, slave->sii_rx_mailbox_size, fp@830: datagram->data + EC_SYNC_PAGE_SIZE * sync.index); fp@830: fp@830: ec_sync_init(&sync, slave, 1); fp@830: sync.physical_start_address = slave->sii_tx_mailbox_offset; fp@830: sync.control_register = 0x22; fp@830: sync.enable = 1; fp@830: ec_sync_config(&sync, slave->sii_tx_mailbox_size, fp@830: datagram->data + EC_SYNC_PAGE_SIZE * sync.index); fp@830: } fp@830: fp@830: fsm->retries = EC_FSM_RETRIES; fp@830: fsm->state = ec_fsm_slave_config_state_mbox_sync; fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** fp@830: Slave configuration state: SYNC. fp@830: */ fp@830: fp@830: void ec_fsm_slave_config_state_mbox_sync(ec_fsm_slave_config_t *fsm /**< slave state machine */) fp@830: { fp@830: ec_datagram_t *datagram = fsm->datagram; fp@830: ec_slave_t *slave = fsm->slave; fp@830: fp@830: if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) fp@830: return; fp@830: fp@830: if (datagram->state != EC_DATAGRAM_RECEIVED) { fp@830: fsm->state = ec_fsm_slave_config_state_error; fp@830: EC_ERR("Failed to receive sync manager configuration datagram for" fp@830: " slave %i (datagram state %i).\n", fp@830: slave->ring_position, datagram->state); fp@830: return; fp@830: } fp@830: fp@830: if (datagram->working_counter != 1) { fp@830: slave->error_flag = 1; fp@830: fsm->state = ec_fsm_slave_config_state_error; fp@830: EC_ERR("Failed to set sync managers of slave %i: ", fp@830: slave->ring_position); fp@830: ec_datagram_print_wc_error(datagram); fp@830: return; fp@830: } fp@830: fp@830: ec_fsm_slave_config_enter_preop(fsm); fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** fp@830: * Request PREOP state. fp@830: */ fp@830: fp@830: void ec_fsm_slave_config_enter_preop(ec_fsm_slave_config_t *fsm /**< slave state machine */) fp@830: { fp@830: fsm->state = ec_fsm_slave_config_state_preop; fp@830: ec_fsm_change_start(&fsm->fsm_change, fsm->slave, EC_SLAVE_STATE_PREOP); fp@830: ec_fsm_change_exec(&fsm->fsm_change); // execute immediately fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** fp@830: Slave configuration state: PREOP. fp@830: */ fp@830: fp@830: void ec_fsm_slave_config_state_preop(ec_fsm_slave_config_t *fsm /**< slave state machine */) fp@830: { fp@830: ec_slave_t *slave = fsm->slave; fp@830: ec_master_t *master = fsm->slave->master; fp@830: fp@830: if (ec_fsm_change_exec(&fsm->fsm_change)) return; fp@830: fp@830: if (!ec_fsm_change_success(&fsm->fsm_change)) { fp@830: if (!fsm->fsm_change.spontaneous_change) fp@830: slave->error_flag = 1; fp@830: fsm->state = ec_fsm_slave_config_state_error; fp@830: return; fp@830: } fp@830: fp@830: // slave is now in PREOP fp@830: slave->jiffies_preop = fsm->datagram->jiffies_received; fp@830: fp@830: if (master->debug_level) { fp@830: EC_DBG("Slave %i is now in PREOP.\n", slave->ring_position); fp@830: } fp@830: fp@830: if (slave->current_state == slave->requested_state) { fp@830: fsm->state = ec_fsm_slave_config_state_end; // successful fp@830: if (master->debug_level) { fp@830: EC_DBG("Finished configuration of slave %i.\n", fp@830: slave->ring_position); fp@830: } fp@830: return; fp@830: } fp@830: fp@830: ec_fsm_slave_config_enter_sdo_conf(fsm); fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** fp@830: * Check for Sdo configurations to be applied. fp@830: */ fp@830: fp@830: void ec_fsm_slave_config_enter_sdo_conf(ec_fsm_slave_config_t *fsm /**< slave state machine */) fp@830: { fp@830: ec_slave_t *slave = fsm->slave; fp@830: fp@830: if (!slave->config) { fp@830: EC_DBG("Slave %u is not configured.\n", slave->ring_position); fp@830: ec_fsm_slave_config_enter_safeop(fsm); fp@830: return; fp@830: } fp@830: fp@830: // No CoE configuration to be applied? fp@830: if (list_empty(&slave->config->sdo_configs)) { // skip Sdo configuration fp@830: ec_fsm_slave_config_enter_mapping(fsm); fp@830: return; fp@830: } fp@830: fp@830: // start Sdo configuration fp@830: fsm->state = ec_fsm_slave_config_state_sdo_conf; fp@830: fsm->sdodata = fp@830: list_entry(fsm->slave->config->sdo_configs.next, ec_sdo_data_t, list); fp@830: ec_fsm_coe_download(&fsm->fsm_coe, fsm->slave, fsm->sdodata); fp@830: ec_fsm_coe_exec(&fsm->fsm_coe); // execute immediately fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** fp@830: Slave configuration state: SDO_CONF. fp@830: */ fp@830: fp@830: void ec_fsm_slave_config_state_sdo_conf( fp@830: ec_fsm_slave_config_t *fsm /**< slave state machine */ fp@830: ) fp@830: { fp@830: if (ec_fsm_coe_exec(&fsm->fsm_coe)) return; fp@830: fp@830: if (!ec_fsm_coe_success(&fsm->fsm_coe)) { fp@830: EC_ERR("Sdo configuration failed for slave %u.\n", fp@830: fsm->slave->ring_position); fp@830: fsm->slave->error_flag = 1; fp@830: fsm->state = ec_fsm_slave_config_state_error; fp@830: return; fp@830: } fp@830: fp@830: // Another Sdo to configure? fp@830: if (fsm->sdodata->list.next != &fsm->slave->config->sdo_configs) { fp@830: fsm->sdodata = fp@830: list_entry(fsm->sdodata->list.next, ec_sdo_data_t, list); fp@830: ec_fsm_coe_download(&fsm->fsm_coe, fsm->slave, fsm->sdodata); fp@830: ec_fsm_coe_exec(&fsm->fsm_coe); // execute immediately fp@830: return; fp@830: } fp@830: fp@830: // All Sdos are now configured. fp@830: ec_fsm_slave_config_enter_mapping(fsm); fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** fp@830: * Check for Pdo mappings to be applied. fp@830: */ fp@830: fp@830: void ec_fsm_slave_config_enter_mapping( fp@830: ec_fsm_slave_config_t *fsm /**< slave state machine */ fp@830: ) fp@830: { fp@830: // start configuring Pdo mapping fp@830: fsm->state = ec_fsm_slave_config_state_mapping; fp@830: ec_fsm_pdo_mapping_start(&fsm->fsm_pdo_map, fsm->slave); fp@830: ec_fsm_pdo_mapping_exec(&fsm->fsm_pdo_map); // execute immediately fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** fp@830: Slave configuration state: MAPPING. fp@830: */ fp@830: fp@830: void ec_fsm_slave_config_state_mapping( fp@830: ec_fsm_slave_config_t *fsm /**< slave state machine */ fp@830: ) fp@830: { fp@830: if (ec_fsm_pdo_mapping_exec(&fsm->fsm_pdo_map)) return; fp@830: fp@830: if (!ec_fsm_pdo_mapping_success(&fsm->fsm_pdo_map)) { fp@830: EC_ERR("Pdo mapping configuration failed for slave %u.\n", fp@830: fsm->slave->ring_position); fp@830: fsm->slave->error_flag = 1; fp@830: fsm->state = ec_fsm_slave_config_state_error; fp@830: return; fp@830: } fp@830: fp@830: // Start Pdo configuration fp@830: fsm->state = ec_fsm_slave_config_state_pdo_conf; fp@830: ec_fsm_pdo_config_start(&fsm->fsm_pdo_conf, fsm->slave); fp@830: ec_fsm_pdo_config_exec(&fsm->fsm_pdo_conf); // execute immediately fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** fp@830: Slave configuration state: PDO_CONF. fp@830: */ fp@830: fp@830: void ec_fsm_slave_config_state_pdo_conf( fp@830: ec_fsm_slave_config_t *fsm /**< slave state machine */ fp@830: ) fp@830: { fp@830: if (ec_fsm_pdo_config_exec(&fsm->fsm_pdo_conf)) return; fp@830: fp@830: if (!ec_fsm_pdo_config_success(&fsm->fsm_pdo_conf)) { fp@830: EC_ERR("Pdo configuration failed for slave %u.\n", fp@830: fsm->slave->ring_position); fp@830: fsm->slave->error_flag = 1; fp@830: fsm->state = ec_fsm_slave_config_state_error; fp@830: return; fp@830: } fp@830: fp@830: ec_fsm_slave_config_enter_pdo_sync(fsm); fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** fp@830: * Check for Pdo sync managers to be configured. fp@830: */ fp@830: fp@830: void ec_fsm_slave_config_enter_pdo_sync( fp@830: ec_fsm_slave_config_t *fsm /**< slave state machine */ fp@830: ) fp@830: { fp@830: ec_slave_t *slave = fsm->slave; fp@830: ec_datagram_t *datagram = fsm->datagram; fp@830: unsigned int i, offset, num_syncs; fp@830: const ec_sync_t *sync; fp@830: ec_direction_t dir; fp@830: uint16_t size; fp@830: fp@830: if (!slave->sii_sync_count) { fp@830: ec_fsm_slave_config_enter_fmmu(fsm); fp@830: return; fp@830: } fp@830: fp@830: if (slave->sii_mailbox_protocols) { fp@830: offset = 2; // slave has mailboxes fp@830: } else { fp@830: offset = 0; fp@830: } fp@830: num_syncs = slave->sii_sync_count - offset; fp@830: fp@830: // configure sync managers for process data fp@830: ec_datagram_fpwr(datagram, slave->station_address, fp@830: 0x0800 + EC_SYNC_PAGE_SIZE * offset, fp@830: EC_SYNC_PAGE_SIZE * num_syncs); fp@830: memset(datagram->data, 0x00, EC_SYNC_PAGE_SIZE * num_syncs); fp@830: fp@830: for (i = 0; i < num_syncs; i++) { fp@830: sync = &slave->sii_syncs[i + offset]; fp@830: dir = ec_sync_direction(sync); fp@830: size = ec_pdo_mapping_total_size(&slave->config->mapping[dir]); fp@830: ec_sync_config(sync, size, datagram->data + EC_SYNC_PAGE_SIZE * i); fp@830: } fp@830: fp@830: fsm->retries = EC_FSM_RETRIES; fp@830: fsm->state = ec_fsm_slave_config_state_pdo_sync; fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** fp@830: * Configure Pdo sync managers. fp@830: */ fp@830: fp@830: void ec_fsm_slave_config_state_pdo_sync(ec_fsm_slave_config_t *fsm /**< slave state machine */) fp@830: { fp@830: ec_datagram_t *datagram = fsm->datagram; fp@830: ec_slave_t *slave = fsm->slave; fp@830: fp@830: if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) fp@830: return; fp@830: fp@830: if (datagram->state != EC_DATAGRAM_RECEIVED) { fp@830: fsm->state = ec_fsm_slave_config_state_error; fp@830: EC_ERR("Failed to receive process data sync manager configuration" fp@830: " datagram for slave %i (datagram state %i).\n", fp@830: slave->ring_position, datagram->state); fp@830: return; fp@830: } fp@830: fp@830: if (datagram->working_counter != 1) { fp@830: slave->error_flag = 1; fp@830: fsm->state = ec_fsm_slave_config_state_error; fp@830: EC_ERR("Failed to set process data sync managers of slave %i: ", fp@830: slave->ring_position); fp@830: ec_datagram_print_wc_error(datagram); fp@830: return; fp@830: } fp@830: fp@830: ec_fsm_slave_config_enter_fmmu(fsm); fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** fp@830: * Check for FMMUs to be configured. fp@830: */ fp@830: fp@830: void ec_fsm_slave_config_enter_fmmu(ec_fsm_slave_config_t *fsm /**< slave state machine */) fp@830: { fp@830: ec_slave_t *slave = fsm->slave; fp@830: ec_datagram_t *datagram = fsm->datagram; fp@830: unsigned int i; fp@830: const ec_fmmu_config_t *fmmu; fp@830: const ec_sync_t *sync; fp@830: fp@830: if (slave->base_fmmu_count < slave->config->used_fmmus) { fp@830: slave->error_flag = 1; fp@830: fsm->state = ec_fsm_slave_config_state_error; fp@830: EC_ERR("Slave %u has less FMMUs (%u) than requested (%u).\n", fp@830: slave->ring_position, slave->base_fmmu_count, fp@830: slave->config->used_fmmus); fp@830: return; fp@830: } fp@830: fp@830: if (!slave->base_fmmu_count) { // skip FMMU configuration fp@830: ec_fsm_slave_config_enter_safeop(fsm); fp@830: return; fp@830: } fp@830: fp@830: // configure FMMUs fp@830: ec_datagram_fpwr(datagram, slave->station_address, fp@830: 0x0600, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count); fp@830: memset(datagram->data, 0x00, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count); fp@830: for (i = 0; i < slave->config->used_fmmus; i++) { fp@830: fmmu = &slave->config->fmmu_configs[i]; fp@830: if (!(sync = ec_slave_get_pdo_sync(slave, fmmu->dir))) { fp@830: slave->error_flag = 1; fp@830: fsm->state = ec_fsm_slave_config_state_error; fp@830: EC_ERR("Failed to determine Pdo sync manager for FMMU on slave" fp@830: " %u!\n", slave->ring_position); fp@830: return; fp@830: } fp@830: ec_fmmu_config_page(fmmu, sync, fp@830: datagram->data + EC_FMMU_PAGE_SIZE * i); fp@830: } fp@830: fp@830: fsm->retries = EC_FSM_RETRIES; fp@830: fsm->state = ec_fsm_slave_config_state_fmmu; fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** fp@830: Slave configuration state: FMMU. fp@830: */ fp@830: fp@830: void ec_fsm_slave_config_state_fmmu(ec_fsm_slave_config_t *fsm /**< slave state machine */) fp@830: { fp@830: ec_datagram_t *datagram = fsm->datagram; fp@830: ec_slave_t *slave = fsm->slave; fp@830: fp@830: if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) fp@830: return; fp@830: fp@830: if (datagram->state != EC_DATAGRAM_RECEIVED) { fp@830: fsm->state = ec_fsm_slave_config_state_error; fp@830: EC_ERR("Failed to receive FMMUs datagram for slave %i" fp@830: " (datagram state %i).\n", fp@830: slave->ring_position, datagram->state); fp@830: return; fp@830: } fp@830: fp@830: if (datagram->working_counter != 1) { fp@830: slave->error_flag = 1; fp@830: fsm->state = ec_fsm_slave_config_state_error; fp@830: EC_ERR("Failed to set FMMUs of slave %i: ", fp@830: slave->ring_position); fp@830: ec_datagram_print_wc_error(datagram); fp@830: return; fp@830: } fp@830: fp@830: ec_fsm_slave_config_enter_safeop(fsm); fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** fp@830: * Request SAFEOP state. fp@830: */ fp@830: fp@830: void ec_fsm_slave_config_enter_safeop(ec_fsm_slave_config_t *fsm /**< slave state machine */) fp@830: { fp@830: fsm->state = ec_fsm_slave_config_state_safeop; fp@830: ec_fsm_change_start(&fsm->fsm_change, fsm->slave, EC_SLAVE_STATE_SAFEOP); fp@830: ec_fsm_change_exec(&fsm->fsm_change); // execute immediately fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** fp@830: Slave configuration state: SAFEOP. fp@830: */ fp@830: fp@830: void ec_fsm_slave_config_state_safeop(ec_fsm_slave_config_t *fsm /**< slave state machine */) fp@830: { fp@830: ec_master_t *master = fsm->slave->master; fp@830: ec_slave_t *slave = fsm->slave; fp@830: fp@830: if (ec_fsm_change_exec(&fsm->fsm_change)) return; fp@830: fp@830: if (!ec_fsm_change_success(&fsm->fsm_change)) { fp@830: if (!fsm->fsm_change.spontaneous_change) fp@830: fsm->slave->error_flag = 1; fp@830: fsm->state = ec_fsm_slave_config_state_error; fp@830: return; fp@830: } fp@830: fp@830: // slave is now in SAFEOP fp@830: fp@830: if (master->debug_level) { fp@830: EC_DBG("Slave %i is now in SAFEOP.\n", slave->ring_position); fp@830: } fp@830: fp@830: if (fsm->slave->current_state == fsm->slave->requested_state) { fp@830: fsm->state = ec_fsm_slave_config_state_end; // successful fp@830: if (master->debug_level) { fp@830: EC_DBG("Finished configuration of slave %i.\n", fp@830: slave->ring_position); fp@830: } fp@830: return; fp@830: } fp@830: fp@830: // set state to OP fp@830: fsm->state = ec_fsm_slave_config_state_op; fp@830: ec_fsm_change_start(&fsm->fsm_change, slave, EC_SLAVE_STATE_OP); fp@830: ec_fsm_change_exec(&fsm->fsm_change); // execute immediately fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** fp@830: Slave configuration state: OP fp@830: */ fp@830: fp@830: void ec_fsm_slave_config_state_op(ec_fsm_slave_config_t *fsm /**< slave state machine */) fp@830: { fp@830: ec_master_t *master = fsm->slave->master; fp@830: ec_slave_t *slave = fsm->slave; fp@830: fp@830: if (ec_fsm_change_exec(&fsm->fsm_change)) return; fp@830: fp@830: if (!ec_fsm_change_success(&fsm->fsm_change)) { fp@830: if (!fsm->fsm_change.spontaneous_change) fp@830: slave->error_flag = 1; fp@830: fsm->state = ec_fsm_slave_config_state_error; fp@830: return; fp@830: } fp@830: fp@830: // slave is now in OP fp@830: fp@830: if (master->debug_level) { fp@830: EC_DBG("Slave %i is now in OP.\n", slave->ring_position); fp@830: EC_DBG("Finished configuration of slave %i.\n", slave->ring_position); fp@830: } fp@830: fp@830: fsm->state = ec_fsm_slave_config_state_end; // successful fp@830: } fp@830: fp@830: /****************************************************************************** fp@830: * Common state functions fp@830: *****************************************************************************/ fp@830: fp@830: /** fp@830: State: ERROR. fp@830: */ fp@830: fp@830: void ec_fsm_slave_config_state_error(ec_fsm_slave_config_t *fsm /**< slave state machine */) fp@830: { fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** fp@830: State: END. fp@830: */ fp@830: fp@830: void ec_fsm_slave_config_state_end(ec_fsm_slave_config_t *fsm /**< slave state machine */) fp@830: { fp@830: } fp@830: fp@830: /*****************************************************************************/