fp@830: /****************************************************************************** fp@830: * fp@830: * $Id$ fp@830: * fp@1326: * Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH fp@830: * fp@830: * This file is part of the IgH EtherCAT Master. fp@830: * fp@1326: * The IgH EtherCAT Master is free software; you can redistribute it and/or fp@1326: * modify it under the terms of the GNU General Public License version 2, as fp@1326: * published by the Free Software Foundation. fp@1326: * fp@1326: * The IgH EtherCAT Master is distributed in the hope that it will be useful, fp@1326: * but WITHOUT ANY WARRANTY; without even the implied warranty of fp@1326: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General fp@1326: * Public License for more details. fp@1326: * fp@1326: * You should have received a copy of the GNU General Public License along fp@1326: * 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@1363: * --- fp@1363: * fp@1363: * The license mentioned above concerns the source code only. Using the fp@1363: * EtherCAT technology and brand is only permitted in compliance with the fp@1363: * industrial property and similar rights of Beckhoff Automation GmbH. fp@830: * fp@830: *****************************************************************************/ fp@830: fp@830: /** fp@830: \file fp@830: EtherCAT slave state machines. 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: fp@830: #include "fsm_slave_scan.h" fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: void ec_fsm_slave_scan_state_start(ec_fsm_slave_scan_t *); fp@830: void ec_fsm_slave_scan_state_address(ec_fsm_slave_scan_t *); fp@830: void ec_fsm_slave_scan_state_state(ec_fsm_slave_scan_t *); fp@830: void ec_fsm_slave_scan_state_base(ec_fsm_slave_scan_t *); fp@1419: void ec_fsm_slave_scan_state_dc_cap(ec_fsm_slave_scan_t *); fp@1420: void ec_fsm_slave_scan_state_dc_times(ec_fsm_slave_scan_t *); fp@830: void ec_fsm_slave_scan_state_datalink(ec_fsm_slave_scan_t *); fp@872: void ec_fsm_slave_scan_state_sii_size(ec_fsm_slave_scan_t *); fp@872: void ec_fsm_slave_scan_state_sii_data(ec_fsm_slave_scan_t *); fp@1934: #ifdef EC_REGALIAS martin@1579: void ec_fsm_slave_scan_state_regalias(ec_fsm_slave_scan_t *); fp@1934: #endif fp@831: void ec_fsm_slave_scan_state_preop(ec_fsm_slave_scan_t *); fp@1338: void ec_fsm_slave_scan_state_sync(ec_fsm_slave_scan_t *); fp@831: void ec_fsm_slave_scan_state_pdos(ec_fsm_slave_scan_t *); fp@830: fp@830: void ec_fsm_slave_scan_state_end(ec_fsm_slave_scan_t *); fp@830: void ec_fsm_slave_scan_state_error(ec_fsm_slave_scan_t *); fp@830: fp@1419: void ec_fsm_slave_scan_enter_datalink(ec_fsm_slave_scan_t *); fp@1934: #ifdef EC_REGALIAS martin@1579: void ec_fsm_slave_scan_enter_regalias(ec_fsm_slave_scan_t *); fp@1934: #endif fp@831: void ec_fsm_slave_scan_enter_preop(ec_fsm_slave_scan_t *); fp@831: void ec_fsm_slave_scan_enter_pdos(ec_fsm_slave_scan_t *); fp@831: fp@830: /*****************************************************************************/ fp@830: fp@830: /** Constructor. fp@830: */ fp@831: void ec_fsm_slave_scan_init( fp@831: ec_fsm_slave_scan_t *fsm, /**< Slave scanning state machine. */ fp@831: ec_datagram_t *datagram, /**< Datagram to use. */ fp@831: ec_fsm_slave_config_t *fsm_slave_config, /**< Slave configuration fp@831: state machine to use. */ fp@1327: ec_fsm_pdo_t *fsm_pdo /**< PDO configuration machine to use. */ fp@830: ) fp@830: { fp@830: fsm->datagram = datagram; fp@831: fsm->fsm_slave_config = fsm_slave_config; fp@1174: fsm->fsm_pdo = fsm_pdo; fp@830: fp@830: // init sub state machines fp@830: ec_fsm_sii_init(&fsm->fsm_sii, fsm->datagram); fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** Destructor. fp@830: */ fp@830: void ec_fsm_slave_scan_clear(ec_fsm_slave_scan_t *fsm /**< slave state machine */) fp@830: { fp@830: // clear sub state machines fp@830: ec_fsm_sii_clear(&fsm->fsm_sii); fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** fp@830: * Start slave scan state machine. fp@830: */ fp@830: fp@830: void ec_fsm_slave_scan_start( fp@830: ec_fsm_slave_scan_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_scan_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_scan_running(const ec_fsm_slave_scan_t *fsm /**< slave state machine */) fp@830: { fp@830: return fsm->state != ec_fsm_slave_scan_state_end fp@830: && fsm->state != ec_fsm_slave_scan_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_scan_exec(ec_fsm_slave_scan_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_scan_running(fsm); fp@830: } fp@830: fp@830: fsm->state(fsm); fp@830: return ec_fsm_slave_scan_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_scan_success(const ec_fsm_slave_scan_t *fsm /**< slave state machine */) fp@830: { fp@830: return fsm->state == ec_fsm_slave_scan_state_end; fp@830: } fp@830: fp@830: /****************************************************************************** fp@830: * slave scan state machine fp@830: *****************************************************************************/ fp@830: fp@830: /** fp@830: Slave scan state: START. fp@830: First state of the slave state machine. Writes the station address to the fp@830: slave, according to its ring position. fp@830: */ fp@830: fp@830: void ec_fsm_slave_scan_state_start(ec_fsm_slave_scan_t *fsm /**< slave state machine */) fp@830: { fp@830: // write station address fp@830: ec_datagram_apwr(fsm->datagram, fsm->slave->ring_position, 0x0010, 2); fp@830: EC_WRITE_U16(fsm->datagram->data, fsm->slave->station_address); fp@830: fsm->retries = EC_FSM_RETRIES; fp@830: fsm->state = ec_fsm_slave_scan_state_address; fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** fp@830: Slave scan state: ADDRESS. fp@830: */ fp@830: fp@1822: void ec_fsm_slave_scan_state_address( fp@1822: ec_fsm_slave_scan_t *fsm /**< slave state machine */ fp@1822: ) 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_scan_state_error; fp@1921: EC_SLAVE_ERR(fsm->slave, fp@1921: "Failed to receive station address datagram: "); fp@1822: ec_datagram_print_state(datagram); 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_scan_state_error; fp@1921: EC_SLAVE_ERR(fsm->slave, "Failed to write station address: "); fp@830: ec_datagram_print_wc_error(datagram); fp@830: return; fp@830: } fp@830: fp@830: // Read AL state fp@830: ec_datagram_fprd(datagram, fsm->slave->station_address, 0x0130, 2); fp@1225: ec_datagram_zero(datagram); fp@830: fsm->retries = EC_FSM_RETRIES; fp@830: fsm->state = ec_fsm_slave_scan_state_state; fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** fp@830: Slave scan state: STATE. fp@830: */ fp@830: fp@830: void ec_fsm_slave_scan_state_state( fp@830: ec_fsm_slave_scan_t *fsm /**< slave state machine */ fp@830: ) 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_scan_state_error; fp@1921: EC_SLAVE_ERR(slave, "Failed to receive AL state datagram: "); fp@1822: ec_datagram_print_state(datagram); 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_scan_state_error; fp@1921: EC_SLAVE_ERR(slave, "Failed to read AL state: "); fp@830: ec_datagram_print_wc_error(datagram); fp@830: return; fp@830: } fp@830: fp@830: slave->current_state = EC_READ_U8(datagram->data); fp@830: if (slave->current_state & EC_SLAVE_STATE_ACK_ERR) { fp@830: char state_str[EC_STATE_STRING_SIZE]; fp@1337: ec_state_string(slave->current_state, state_str, 0); fp@1921: EC_SLAVE_WARN(slave, "Slave has state error bit set (%s)!\n", fp@1921: state_str); fp@830: } fp@830: fp@830: // read base data fp@1379: ec_datagram_fprd(datagram, fsm->slave->station_address, 0x0000, 12); fp@1225: ec_datagram_zero(datagram); fp@830: fsm->retries = EC_FSM_RETRIES; fp@830: fsm->state = ec_fsm_slave_scan_state_base; fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@1420: /** Slave scan state: BASE. fp@1420: */ fp@1420: void ec_fsm_slave_scan_state_base( fp@1420: ec_fsm_slave_scan_t *fsm /**< slave state machine */ fp@1420: ) fp@830: { fp@830: ec_datagram_t *datagram = fsm->datagram; fp@830: ec_slave_t *slave = fsm->slave; fp@1379: u8 octet; fp@1379: int i; 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_scan_state_error; fp@1921: EC_SLAVE_ERR(slave, "Failed to receive base data datagram: "); fp@1822: ec_datagram_print_state(datagram); 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_scan_state_error; fp@1921: EC_SLAVE_ERR(slave, "Failed to read base data: "); fp@830: ec_datagram_print_wc_error(datagram); fp@830: return; fp@830: } fp@830: fp@830: slave->base_type = EC_READ_U8 (datagram->data); fp@830: slave->base_revision = EC_READ_U8 (datagram->data + 1); fp@830: slave->base_build = EC_READ_U16(datagram->data + 2); fp@1379: fp@830: slave->base_fmmu_count = EC_READ_U8 (datagram->data + 4); fp@830: if (slave->base_fmmu_count > EC_MAX_FMMUS) { fp@1921: EC_SLAVE_WARN(slave, "Slave has more FMMUs (%u) than the master can" fp@1921: " handle (%u).\n", slave->base_fmmu_count, EC_MAX_FMMUS); fp@830: slave->base_fmmu_count = EC_MAX_FMMUS; fp@830: } fp@830: fp@1470: slave->base_sync_count = EC_READ_U8(datagram->data + 5); fp@1379: if (slave->base_sync_count > EC_MAX_SYNC_MANAGERS) { fp@1921: EC_SLAVE_WARN(slave, "Slave provides more sync managers (%u)" fp@1921: " than the master can handle (%u).\n", fp@1379: slave->base_sync_count, EC_MAX_SYNC_MANAGERS); fp@1379: slave->base_sync_count = EC_MAX_SYNC_MANAGERS; fp@1379: } fp@1379: fp@1379: octet = EC_READ_U8(datagram->data + 7); fp@1379: for (i = 0; i < EC_MAX_PORTS; i++) { fp@1425: slave->ports[i].desc = (octet >> (2 * i)) & 0x03; fp@1379: } martin@1579: fp@1379: octet = EC_READ_U8(datagram->data + 8); fp@1379: slave->base_fmmu_bit_operation = octet & 0x01; fp@1379: slave->base_dc_supported = (octet >> 2) & 0x01; fp@1379: slave->base_dc_range = ((octet >> 3) & 0x01) ? EC_DC_64 : EC_DC_32; fp@1379: fp@1419: if (slave->base_dc_supported) { fp@1419: // read DC capabilities fp@1419: ec_datagram_fprd(datagram, slave->station_address, 0x0910, fp@1419: slave->base_dc_range == EC_DC_64 ? 8 : 4); fp@1419: ec_datagram_zero(datagram); fp@1419: fsm->retries = EC_FSM_RETRIES; fp@1419: fsm->state = ec_fsm_slave_scan_state_dc_cap; fp@1419: } else { fp@1419: ec_fsm_slave_scan_enter_datalink(fsm); fp@1419: } fp@1419: } fp@1419: fp@1419: /*****************************************************************************/ fp@1419: fp@1419: /** fp@1419: Slave scan state: DC CAPABILITIES. fp@1419: */ fp@1419: fp@1419: void ec_fsm_slave_scan_state_dc_cap( fp@1419: ec_fsm_slave_scan_t *fsm /**< slave state machine */ fp@1419: ) fp@1419: { fp@1419: ec_datagram_t *datagram = fsm->datagram; fp@1419: ec_slave_t *slave = fsm->slave; fp@1419: fp@1419: if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) fp@1419: return; fp@1419: fp@1419: if (datagram->state != EC_DATAGRAM_RECEIVED) { fp@1419: fsm->state = ec_fsm_slave_scan_state_error; fp@1921: EC_SLAVE_ERR(slave, "Failed to receive system time datagram: "); fp@1822: ec_datagram_print_state(datagram); fp@1419: return; fp@1419: } fp@1419: fp@1419: if (datagram->working_counter == 1) { fp@1419: slave->has_dc_system_time = 1; fp@1921: EC_SLAVE_DBG(slave, 1, "Slave has the System Time register.\n"); fp@1419: } else if (datagram->working_counter == 0) { fp@1921: EC_SLAVE_DBG(slave, 1, "Slave has no System Time register; delay " fp@1921: "measurement only.\n"); fp@1419: } else { fp@1419: fsm->slave->error_flag = 1; fp@1419: fsm->state = ec_fsm_slave_scan_state_error; fp@1921: EC_SLAVE_ERR(slave, "Failed to determine, if system time register is " fp@1921: "supported: "); fp@1419: ec_datagram_print_wc_error(datagram); fp@1419: return; fp@1419: } fp@1419: fp@1420: // read DC port receive times fp@1420: ec_datagram_fprd(datagram, slave->station_address, 0x0900, 16); fp@1420: ec_datagram_zero(datagram); fp@1420: fsm->retries = EC_FSM_RETRIES; fp@1420: fsm->state = ec_fsm_slave_scan_state_dc_times; fp@1420: } fp@1420: fp@1420: /*****************************************************************************/ fp@1420: fp@1420: /** fp@1420: Slave scan state: DC TIMES. fp@1420: */ fp@1420: fp@1420: void ec_fsm_slave_scan_state_dc_times( fp@1420: ec_fsm_slave_scan_t *fsm /**< slave state machine */ fp@1420: ) fp@1420: { fp@1420: ec_datagram_t *datagram = fsm->datagram; fp@1420: ec_slave_t *slave = fsm->slave; fp@1420: int i; fp@1420: fp@1420: if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) fp@1420: return; fp@1420: fp@1420: if (datagram->state != EC_DATAGRAM_RECEIVED) { fp@1420: fsm->state = ec_fsm_slave_scan_state_error; fp@1921: EC_SLAVE_ERR(slave, "Failed to receive system time datagram: "); fp@1822: ec_datagram_print_state(datagram); fp@1420: return; fp@1420: } fp@1420: fp@1420: if (datagram->working_counter != 1) { fp@1420: fsm->slave->error_flag = 1; fp@1420: fsm->state = ec_fsm_slave_scan_state_error; fp@1921: EC_SLAVE_ERR(slave, "Failed to get DC receive times: "); fp@1420: ec_datagram_print_wc_error(datagram); fp@1420: return; fp@1420: } fp@1420: fp@1420: for (i = 0; i < EC_MAX_PORTS; i++) { fp@1425: slave->ports[i].receive_time = EC_READ_U32(datagram->data + 4 * i); fp@1420: } fp@1420: fp@1419: ec_fsm_slave_scan_enter_datalink(fsm); fp@1419: } fp@1419: fp@1419: /*****************************************************************************/ fp@1419: fp@1419: /** fp@1419: Slave scan entry function: DATALINK. fp@1419: */ fp@1419: fp@1419: void ec_fsm_slave_scan_enter_datalink( fp@1419: ec_fsm_slave_scan_t *fsm /**< slave state machine */ fp@1419: ) fp@1419: { fp@1419: ec_datagram_t *datagram = fsm->datagram; fp@1419: ec_slave_t *slave = fsm->slave; fp@1419: fp@830: // read data link status fp@830: ec_datagram_fprd(datagram, slave->station_address, 0x0110, 2); fp@1225: ec_datagram_zero(datagram); fp@830: fsm->retries = EC_FSM_RETRIES; fp@830: fsm->state = ec_fsm_slave_scan_state_datalink; fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** fp@830: Slave scan state: DATALINK. fp@830: */ fp@830: fp@830: void ec_fsm_slave_scan_state_datalink(ec_fsm_slave_scan_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: uint16_t dl_status; fp@830: unsigned int i; 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_scan_state_error; fp@1921: EC_SLAVE_ERR(slave, "Failed to receive DL status datagram: "); fp@1822: ec_datagram_print_state(datagram); 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_scan_state_error; fp@1921: EC_SLAVE_ERR(slave, "Failed to read DL status: "); fp@830: ec_datagram_print_wc_error(datagram); fp@830: return; fp@830: } fp@830: fp@830: dl_status = EC_READ_U16(datagram->data); fp@1055: for (i = 0; i < EC_MAX_PORTS; i++) { fp@1921: slave->ports[i].link.link_up = fp@1921: dl_status & (1 << (4 + i)) ? 1 : 0; fp@1921: slave->ports[i].link.loop_closed = fp@1921: dl_status & (1 << (8 + i * 2)) ? 1 : 0; fp@1921: slave->ports[i].link.signal_detected = fp@1921: dl_status & (1 << (9 + i * 2)) ? 1 : 0; fp@830: } fp@830: fp@872: // Start fetching SII size fp@872: fp@872: fsm->sii_offset = EC_FIRST_SII_CATEGORY_OFFSET; // first category header fp@830: ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset, fp@830: EC_FSM_SII_USE_CONFIGURED_ADDRESS); fp@872: fsm->state = ec_fsm_slave_scan_state_sii_size; fp@830: fsm->state(fsm); // execute state immediately fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** fp@872: Slave scan state: SII SIZE. fp@872: */ fp@872: fp@872: void ec_fsm_slave_scan_state_sii_size(ec_fsm_slave_scan_t *fsm /**< slave state machine */) fp@830: { fp@830: ec_slave_t *slave = fsm->slave; fp@830: uint16_t cat_type, cat_size; fp@830: fp@1951: if (ec_fsm_sii_exec(&fsm->fsm_sii)) fp@1951: return; fp@830: fp@830: if (!ec_fsm_sii_success(&fsm->fsm_sii)) { fp@830: fsm->slave->error_flag = 1; fp@830: fsm->state = ec_fsm_slave_scan_state_error; fp@1951: EC_SLAVE_ERR(slave, "Failed to determine SII content size:" fp@1958: " Reading word offset 0x%04x failed. Assuming %u words.\n", fp@1958: fsm->sii_offset, EC_FIRST_SII_CATEGORY_OFFSET); fp@1958: slave->sii_nwords = EC_FIRST_SII_CATEGORY_OFFSET; fp@1958: goto alloc_sii; fp@830: } fp@830: fp@830: cat_type = EC_READ_U16(fsm->fsm_sii.value); fp@830: cat_size = EC_READ_U16(fsm->fsm_sii.value + 2); fp@830: fp@830: if (cat_type != 0xFFFF) { // not the last category fp@830: off_t next_offset = 2UL + fsm->sii_offset + cat_size; fp@872: if (next_offset >= EC_MAX_SII_SIZE) { fp@1921: EC_SLAVE_WARN(slave, "SII size exceeds %u words" fp@1921: " (0xffff limiter missing?).\n", EC_MAX_SII_SIZE); fp@830: // cut off category data... fp@977: slave->sii_nwords = EC_FIRST_SII_CATEGORY_OFFSET; fp@872: goto alloc_sii; fp@830: } fp@830: fsm->sii_offset = next_offset; fp@830: ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset, fp@830: EC_FSM_SII_USE_CONFIGURED_ADDRESS); fp@830: ec_fsm_sii_exec(&fsm->fsm_sii); // execute state immediately fp@830: return; fp@830: } fp@830: fp@977: slave->sii_nwords = fsm->sii_offset + 1; fp@872: fp@872: alloc_sii: fp@977: if (slave->sii_words) { fp@1921: EC_SLAVE_WARN(slave, "Freeing old SII data...\n"); fp@977: kfree(slave->sii_words); fp@977: } fp@977: fp@977: if (!(slave->sii_words = fp@998: (uint16_t *) kmalloc(slave->sii_nwords * 2, GFP_KERNEL))) { fp@1921: EC_SLAVE_ERR(slave, "Failed to allocate %zu words of SII data.\n", fp@1921: slave->sii_nwords); fp@977: slave->sii_nwords = 0; fp@830: slave->error_flag = 1; fp@830: fsm->state = ec_fsm_slave_scan_state_error; fp@830: return; fp@830: } fp@830: fp@872: // Start fetching SII contents fp@872: fp@872: fsm->state = ec_fsm_slave_scan_state_sii_data; fp@830: fsm->sii_offset = 0x0000; fp@830: ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset, fp@830: EC_FSM_SII_USE_CONFIGURED_ADDRESS); fp@830: ec_fsm_sii_exec(&fsm->fsm_sii); // execute state immediately fp@830: } fp@830: fp@830: /*****************************************************************************/ fp@830: fp@830: /** fp@872: Slave scan state: SII DATA. fp@872: */ fp@872: fp@872: void ec_fsm_slave_scan_state_sii_data(ec_fsm_slave_scan_t *fsm /**< slave state machine */) fp@830: { fp@830: ec_slave_t *slave = fsm->slave; fp@977: uint16_t *cat_word, cat_type, cat_size; fp@830: fp@830: if (ec_fsm_sii_exec(&fsm->fsm_sii)) return; fp@830: fp@830: if (!ec_fsm_sii_success(&fsm->fsm_sii)) { fp@830: fsm->slave->error_flag = 1; fp@830: fsm->state = ec_fsm_slave_scan_state_error; fp@1921: EC_SLAVE_ERR(slave, "Failed to fetch SII contents.\n"); fp@830: return; fp@830: } fp@830: fp@830: // 2 words fetched fp@830: fp@977: if (fsm->sii_offset + 2 <= slave->sii_nwords) { // 2 words fit fp@977: memcpy(slave->sii_words + fsm->sii_offset, fsm->fsm_sii.value, 4); fp@977: } else { // copy the last word fp@977: memcpy(slave->sii_words + fsm->sii_offset, fsm->fsm_sii.value, 2); fp@977: } fp@977: fp@977: if (fsm->sii_offset + 2 < slave->sii_nwords) { fp@830: // fetch the next 2 words fp@830: fsm->sii_offset += 2; fp@830: ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset, fp@830: EC_FSM_SII_USE_CONFIGURED_ADDRESS); fp@830: ec_fsm_sii_exec(&fsm->fsm_sii); // execute state immediately fp@830: return; fp@830: } fp@830: fp@872: // Evaluate SII contents martin@1579: fp@870: ec_slave_clear_sync_managers(slave); fp@830: fp@834: slave->sii.alias = fp@977: EC_READ_U16(slave->sii_words + 0x0004); fp@1909: slave->effective_alias = slave->sii.alias; fp@834: slave->sii.vendor_id = fp@977: EC_READ_U32(slave->sii_words + 0x0008); fp@834: slave->sii.product_code = fp@977: EC_READ_U32(slave->sii_words + 0x000A); fp@834: slave->sii.revision_number = fp@977: EC_READ_U32(slave->sii_words + 0x000C); fp@834: slave->sii.serial_number = fp@977: EC_READ_U32(slave->sii_words + 0x000E); fp@1337: slave->sii.boot_rx_mailbox_offset = fp@1337: EC_READ_U16(slave->sii_words + 0x0014); fp@1337: slave->sii.boot_rx_mailbox_size = fp@1337: EC_READ_U16(slave->sii_words + 0x0015); fp@1337: slave->sii.boot_tx_mailbox_offset = fp@1337: EC_READ_U16(slave->sii_words + 0x0016); fp@1337: slave->sii.boot_tx_mailbox_size = fp@1337: EC_READ_U16(slave->sii_words + 0x0017); fp@1337: slave->sii.std_rx_mailbox_offset = fp@977: EC_READ_U16(slave->sii_words + 0x0018); fp@1337: slave->sii.std_rx_mailbox_size = fp@977: EC_READ_U16(slave->sii_words + 0x0019); fp@1337: slave->sii.std_tx_mailbox_offset = fp@977: EC_READ_U16(slave->sii_words + 0x001A); fp@1337: slave->sii.std_tx_mailbox_size = fp@977: EC_READ_U16(slave->sii_words + 0x001B); fp@834: slave->sii.mailbox_protocols = fp@977: EC_READ_U16(slave->sii_words + 0x001C); fp@977: fp@977: if (slave->sii_nwords == EC_FIRST_SII_CATEGORY_OFFSET) { fp@872: // sii does not contain category data fp@830: fsm->state = ec_fsm_slave_scan_state_end; fp@830: return; fp@830: } fp@830: fp@977: if (slave->sii_nwords < EC_FIRST_SII_CATEGORY_OFFSET + 1) { fp@1921: EC_SLAVE_ERR(slave, "Unexpected end of SII data:" fp@1921: " First category header missing.\n"); fp@830: goto end; fp@830: } fp@830: fp@830: // evaluate category data fp@977: cat_word = slave->sii_words + EC_FIRST_SII_CATEGORY_OFFSET; fp@830: while (EC_READ_U16(cat_word) != 0xFFFF) { fp@830: fp@830: // type and size words must fit fp@977: if (cat_word + 2 - slave->sii_words > slave->sii_nwords) { fp@1921: EC_SLAVE_ERR(slave, "Unexpected end of SII data:" fp@1921: " Category header incomplete.\n"); fp@830: goto end; fp@830: } fp@830: fp@830: cat_type = EC_READ_U16(cat_word) & 0x7FFF; fp@830: cat_size = EC_READ_U16(cat_word + 1); fp@830: cat_word += 2; fp@830: fp@977: if (cat_word + cat_size - slave->sii_words > slave->sii_nwords) { fp@1921: EC_SLAVE_WARN(slave, "Unexpected end of SII data:" fp@1921: " Category data incomplete.\n"); fp@830: goto end; fp@830: } fp@830: fp@830: switch (cat_type) { fp@830: case 0x000A: fp@830: if (ec_slave_fetch_sii_strings(slave, (uint8_t *) cat_word, fp@830: cat_size * 2)) fp@830: goto end; fp@830: break; fp@830: case 0x001E: fp@830: if (ec_slave_fetch_sii_general(slave, (uint8_t *) cat_word, fp@830: cat_size * 2)) fp@830: goto end; fp@830: break; fp@830: case 0x0028: fp@830: break; fp@830: case 0x0029: fp@830: if (ec_slave_fetch_sii_syncs(slave, (uint8_t *) cat_word, fp@830: cat_size * 2)) fp@830: goto end; fp@830: break; fp@830: case 0x0032: fp@830: if (ec_slave_fetch_sii_pdos( slave, (uint8_t *) cat_word, fp@1327: cat_size * 2, EC_DIR_INPUT)) // TxPDO fp@830: goto end; fp@830: break; fp@830: case 0x0033: fp@830: if (ec_slave_fetch_sii_pdos( slave, (uint8_t *) cat_word, fp@1327: cat_size * 2, EC_DIR_OUTPUT)) // RxPDO fp@830: goto end; fp@830: break; fp@830: default: fp@1924: EC_SLAVE_DBG(slave, 1, "Unknown category type 0x%04X.\n", fp@1924: cat_type); fp@830: } fp@830: fp@830: cat_word += cat_size; fp@977: if (cat_word - slave->sii_words >= slave->sii_nwords) { fp@1921: EC_SLAVE_WARN(slave, "Unexpected end of SII data:" fp@1921: " Next category header missing.\n"); fp@830: goto end; fp@830: } fp@830: } fp@830: fp@1934: #ifdef EC_REGALIAS martin@1579: ec_fsm_slave_scan_enter_regalias(fsm); fp@1934: #else fp@1934: if (slave->sii.mailbox_protocols & EC_MBOX_COE) { fp@1934: ec_fsm_slave_scan_enter_preop(fsm); fp@1934: } else { fp@1934: fsm->state = ec_fsm_slave_scan_state_end; fp@1934: } fp@1934: #endif martin@1579: return; martin@1579: martin@1579: end: fp@1921: EC_SLAVE_ERR(slave, "Failed to analyze category data.\n"); martin@1579: fsm->slave->error_flag = 1; martin@1579: fsm->state = ec_fsm_slave_scan_state_error; martin@1579: } martin@1579: fp@1934: /*****************************************************************************/ fp@1934: fp@1934: #ifdef EC_REGALIAS fp@1934: fp@1934: /** Slave scan entry function: REGALIAS. fp@1934: */ martin@1579: void ec_fsm_slave_scan_enter_regalias( martin@1579: ec_fsm_slave_scan_t *fsm /**< slave state machine */ martin@1579: ) martin@1579: { martin@1579: ec_datagram_t *datagram = fsm->datagram; martin@1579: ec_slave_t *slave = fsm->slave; martin@1579: fp@1909: // read alias from register fp@1921: EC_SLAVE_DBG(slave, 1, "Reading alias from register.\n"); martin@1579: ec_datagram_fprd(datagram, slave->station_address, 0x0012, 2); martin@1579: ec_datagram_zero(datagram); martin@1579: fsm->retries = EC_FSM_RETRIES; martin@1579: fsm->state = ec_fsm_slave_scan_state_regalias; martin@1579: } martin@1579: martin@1579: /*****************************************************************************/ martin@1579: fp@1934: /** Slave scan state: REGALIAS. fp@1934: */ martin@1579: void ec_fsm_slave_scan_state_regalias( martin@1579: ec_fsm_slave_scan_t *fsm /**< slave state machine */ fp@1804: ) martin@1579: { martin@1579: ec_datagram_t *datagram = fsm->datagram; martin@1579: ec_slave_t *slave = fsm->slave; martin@1579: martin@1579: if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) martin@1579: return; martin@1579: martin@1579: if (datagram->state != EC_DATAGRAM_RECEIVED) { martin@1579: fsm->state = ec_fsm_slave_scan_state_error; fp@1921: EC_SLAVE_ERR(slave, "Failed to receive register alias datagram: "); fp@1822: ec_datagram_print_state(datagram); martin@1579: return; martin@1579: } martin@1579: ch1010277@1776: if (datagram->working_counter != 1) { fp@1921: EC_SLAVE_DBG(slave, 1, "Failed to read register alias.\n"); ch1010277@1776: } else { fp@1909: slave->effective_alias = EC_READ_U16(datagram->data); fp@1921: EC_SLAVE_DBG(slave, 1, "Read alias %u from register.\n", fp@1921: slave->effective_alias); ch1010277@1776: } fp@1934: fp@834: if (slave->sii.mailbox_protocols & EC_MBOX_COE) { fp@831: ec_fsm_slave_scan_enter_preop(fsm); fp@831: } else { fp@831: fsm->state = ec_fsm_slave_scan_state_end; fp@831: } fp@830: } fp@830: fp@1934: #endif // defined EC_REGALIAS fp@1934: fp@831: /*****************************************************************************/ fp@831: fp@841: /** Enter slave scan state PREOP. fp@841: */ fp@831: void ec_fsm_slave_scan_enter_preop( fp@831: ec_fsm_slave_scan_t *fsm /**< slave state machine */ fp@831: ) fp@831: { fp@831: ec_slave_t *slave = fsm->slave; fp@1338: uint8_t current_state = slave->current_state & EC_SLAVE_STATE_MASK; fp@1338: fp@1338: if (current_state != EC_SLAVE_STATE_PREOP fp@1338: && current_state != EC_SLAVE_STATE_SAFEOP fp@1338: && current_state != EC_SLAVE_STATE_OP) { fp@1338: if (slave->master->debug_level) { fp@1338: char str[EC_STATE_STRING_SIZE]; fp@1338: ec_state_string(current_state, str, 0); fp@1921: EC_SLAVE_DBG(slave, 0, "Slave is not in the state" fp@1921: " to do mailbox com (%s), setting to PREOP.\n", str); fp@1338: } fp@1338: fp@831: fsm->state = ec_fsm_slave_scan_state_preop; fp@831: ec_slave_request_state(slave, EC_SLAVE_STATE_PREOP); fp@831: ec_fsm_slave_config_start(fsm->fsm_slave_config, slave); fp@831: ec_fsm_slave_config_exec(fsm->fsm_slave_config); fp@831: } else { fp@1921: EC_SLAVE_DBG(slave, 1, "Reading mailbox" fp@1921: " sync manager configuration.\n"); fp@1338: fp@1338: /* Scan current sync manager configuration to get configured mailbox fp@1338: * sizes. */ fp@1338: ec_datagram_fprd(fsm->datagram, slave->station_address, 0x0800, fp@1338: EC_SYNC_PAGE_SIZE * 2); fp@1338: fsm->retries = EC_FSM_RETRIES; fp@1338: fsm->state = ec_fsm_slave_scan_state_sync; fp@831: } fp@831: } fp@831: fp@831: /*****************************************************************************/ fp@831: fp@831: /** Slave scan state: PREOP. fp@831: */ fp@831: void ec_fsm_slave_scan_state_preop( fp@831: ec_fsm_slave_scan_t *fsm /**< slave state machine */ fp@831: ) fp@831: { fp@831: if (ec_fsm_slave_config_exec(fsm->fsm_slave_config)) fp@831: return; fp@831: fp@831: if (!ec_fsm_slave_config_success(fsm->fsm_slave_config)) { fp@831: fsm->state = ec_fsm_slave_scan_state_error; fp@831: return; fp@831: } fp@831: fp@831: ec_fsm_slave_scan_enter_pdos(fsm); fp@831: } fp@831: fp@831: /*****************************************************************************/ fp@831: fp@1338: /** Slave scan state: SYNC. fp@1338: */ fp@1338: void ec_fsm_slave_scan_state_sync( fp@1338: ec_fsm_slave_scan_t *fsm /**< slave state machine */ fp@1338: ) fp@1338: { fp@1338: ec_datagram_t *datagram = fsm->datagram; fp@1338: ec_slave_t *slave = fsm->slave; fp@1338: fp@1338: if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) fp@1338: return; fp@1338: fp@1338: if (datagram->state != EC_DATAGRAM_RECEIVED) { fp@1338: fsm->state = ec_fsm_slave_scan_state_error; fp@1921: EC_SLAVE_ERR(slave, "Failed to receive sync manager" fp@1921: " configuration datagram: "); fp@1822: ec_datagram_print_state(datagram); fp@1338: return; fp@1338: } fp@1338: fp@1338: if (datagram->working_counter != 1) { fp@1338: fsm->slave->error_flag = 1; fp@1338: fsm->state = ec_fsm_slave_scan_state_error; fp@1921: EC_SLAVE_ERR(slave, "Failed to read DL status: "); fp@1338: ec_datagram_print_wc_error(datagram); fp@1338: return; fp@1338: } fp@1338: fp@1338: slave->configured_rx_mailbox_offset = EC_READ_U16(datagram->data); fp@1338: slave->configured_rx_mailbox_size = EC_READ_U16(datagram->data + 2); fp@1338: slave->configured_tx_mailbox_offset = EC_READ_U16(datagram->data + 8); fp@1338: slave->configured_tx_mailbox_size = EC_READ_U16(datagram->data + 10); fp@1338: fp@1921: EC_SLAVE_DBG(slave, 1, "Mailbox configuration:\n"); fp@1921: EC_SLAVE_DBG(slave, 1, " RX offset=0x%04x size=%u\n", fp@1921: slave->configured_rx_mailbox_offset, fp@1921: slave->configured_rx_mailbox_size); fp@1921: EC_SLAVE_DBG(slave, 1, " TX offset=0x%04x size=%u\n", fp@1921: slave->configured_tx_mailbox_offset, fp@1921: slave->configured_tx_mailbox_size); fp@1338: fp@1338: ec_fsm_slave_scan_enter_pdos(fsm); fp@1338: } fp@1338: fp@1338: /*****************************************************************************/ fp@1338: fp@841: /** Enter slave scan state PDOS. fp@841: */ fp@831: void ec_fsm_slave_scan_enter_pdos( fp@831: ec_fsm_slave_scan_t *fsm /**< slave state machine */ fp@831: ) fp@831: { fp@831: ec_slave_t *slave = fsm->slave; fp@831: fp@1921: EC_SLAVE_DBG(slave, 1, "Scanning PDO assignment and mapping.\n"); fp@831: fsm->state = ec_fsm_slave_scan_state_pdos; fp@1174: ec_fsm_pdo_start_reading(fsm->fsm_pdo, slave); fp@1174: ec_fsm_pdo_exec(fsm->fsm_pdo); // execute immediately fp@831: } fp@831: fp@831: /*****************************************************************************/ fp@831: fp@831: /** Slave scan state: PDOS. fp@831: */ fp@831: void ec_fsm_slave_scan_state_pdos( fp@831: ec_fsm_slave_scan_t *fsm /**< slave state machine */ fp@831: ) fp@831: { fp@1174: if (ec_fsm_pdo_exec(fsm->fsm_pdo)) fp@1174: return; fp@1174: fp@1174: if (!ec_fsm_pdo_success(fsm->fsm_pdo)) { fp@1174: fsm->state = ec_fsm_slave_scan_state_error; fp@1174: return; fp@1174: } fp@1174: fp@1327: // reading PDO configuration finished fp@831: fsm->state = ec_fsm_slave_scan_state_end; fp@831: } fp@831: fp@830: /****************************************************************************** fp@830: * Common state functions fp@830: *****************************************************************************/ fp@830: fp@830: /** State: ERROR. fp@830: */ fp@830: void ec_fsm_slave_scan_state_error( fp@830: ec_fsm_slave_scan_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: void ec_fsm_slave_scan_state_end( fp@830: ec_fsm_slave_scan_t *fsm /**< slave state machine */ fp@830: ) fp@830: { fp@830: } fp@830: fp@830: /*****************************************************************************/