martin@1583: /****************************************************************************** martin@1583: * fp@2414: * $Id$ martin@1583: * fp@2589: * Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH martin@1583: * martin@1583: * This file is part of the IgH EtherCAT Master. martin@1583: * martin@1583: * The IgH EtherCAT Master is free software; you can redistribute it and/or martin@1583: * modify it under the terms of the GNU General Public License version 2, as martin@1583: * published by the Free Software Foundation. martin@1583: * martin@1583: * The IgH EtherCAT Master is distributed in the hope that it will be useful, martin@1583: * but WITHOUT ANY WARRANTY; without even the implied warranty of martin@1583: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General martin@1583: * Public License for more details. martin@1583: * martin@1583: * You should have received a copy of the GNU General Public License along martin@1583: * with the IgH EtherCAT Master; if not, write to the Free Software martin@1583: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA martin@1583: * martin@1583: * --- martin@1583: * martin@1583: * The license mentioned above concerns the source code only. Using the martin@1583: * EtherCAT technology and brand is only permitted in compliance with the martin@1583: * industrial property and similar rights of Beckhoff Automation GmbH. martin@1583: * martin@1583: *****************************************************************************/ martin@1583: martin@1583: /** \file martin@1583: * EtherCAT slave (SDO) state machine. martin@1583: */ martin@1583: martin@1583: /*****************************************************************************/ martin@1583: martin@1583: #include "globals.h" martin@1583: #include "master.h" martin@1583: #include "mailbox.h" fp@2589: #include "slave_config.h" martin@1583: martin@1583: #include "fsm_slave.h" martin@1583: martin@1583: /*****************************************************************************/ martin@1583: fp@2589: void ec_fsm_slave_state_idle(ec_fsm_slave_t *, ec_datagram_t *); fp@2589: void ec_fsm_slave_state_ready(ec_fsm_slave_t *, ec_datagram_t *); fp@2589: int ec_fsm_slave_action_process_sdo(ec_fsm_slave_t *, ec_datagram_t *); fp@2589: void ec_fsm_slave_state_sdo_request(ec_fsm_slave_t *, ec_datagram_t *); fp@2589: int ec_fsm_slave_action_process_reg(ec_fsm_slave_t *, ec_datagram_t *); fp@2589: void ec_fsm_slave_state_reg_request(ec_fsm_slave_t *, ec_datagram_t *); fp@2589: int ec_fsm_slave_action_process_foe(ec_fsm_slave_t *, ec_datagram_t *); fp@2589: void ec_fsm_slave_state_foe_request(ec_fsm_slave_t *, ec_datagram_t *); fp@2589: int ec_fsm_slave_action_process_soe(ec_fsm_slave_t *, ec_datagram_t *); fp@2589: void ec_fsm_slave_state_soe_request(ec_fsm_slave_t *, ec_datagram_t *); fp@2597: int ec_fsm_slave_action_process_eoe(ec_fsm_slave_t *, ec_datagram_t *); fp@2597: void ec_fsm_slave_state_eoe_request(ec_fsm_slave_t *, ec_datagram_t *); martin@1583: martin@1583: /*****************************************************************************/ martin@1583: martin@1583: /** Constructor. martin@1583: */ martin@1583: void ec_fsm_slave_init( martin@1583: ec_fsm_slave_t *fsm, /**< Slave state machine. */ fp@2589: ec_slave_t *slave /**< EtherCAT slave. */ martin@1583: ) martin@1583: { martin@1583: fsm->slave = slave; fp@2589: INIT_LIST_HEAD(&fsm->list); // mark as unlisted fp@1804: fp@1804: fsm->state = ec_fsm_slave_state_idle; fp@2589: fsm->datagram = NULL; fp@2589: fsm->sdo_request = NULL; fp@2589: fsm->reg_request = NULL; fp@2589: fsm->foe_request = NULL; fp@2589: fsm->soe_request = NULL; fp@2597: fsm->eoe_request = NULL; fp@2589: fp@2589: // Init sub-state-machines fp@2589: ec_fsm_coe_init(&fsm->fsm_coe); fp@2589: ec_fsm_foe_init(&fsm->fsm_foe); fp@2589: ec_fsm_soe_init(&fsm->fsm_soe); fp@2597: ec_fsm_eoe_init(&fsm->fsm_eoe); martin@1583: } martin@1583: martin@1583: /*****************************************************************************/ martin@1583: martin@1583: /** Destructor. martin@1583: */ martin@1583: void ec_fsm_slave_clear( martin@1583: ec_fsm_slave_t *fsm /**< Master state machine. */ martin@1583: ) martin@1583: { fp@2589: // signal requests that are currently in operation fp@2589: fp@2589: if (fsm->sdo_request) { fp@2589: fsm->sdo_request->state = EC_INT_REQUEST_FAILURE; fp@2589: wake_up_all(&fsm->slave->master->request_queue); fp@2589: } fp@2589: fp@2589: if (fsm->reg_request) { fp@2589: fsm->reg_request->state = EC_INT_REQUEST_FAILURE; fp@2589: wake_up_all(&fsm->slave->master->request_queue); fp@2589: } fp@2589: fp@2589: if (fsm->foe_request) { fp@2589: fsm->foe_request->state = EC_INT_REQUEST_FAILURE; fp@2589: wake_up_all(&fsm->slave->master->request_queue); fp@2589: } fp@2589: fp@2589: if (fsm->soe_request) { fp@2589: fsm->soe_request->state = EC_INT_REQUEST_FAILURE; fp@2589: wake_up_all(&fsm->slave->master->request_queue); fp@2589: } fp@2589: fp@2597: if (fsm->eoe_request) { fp@2597: fsm->soe_request->state = EC_INT_REQUEST_FAILURE; fp@2597: wake_up_all(&fsm->slave->master->request_queue); fp@2597: } fp@2597: martin@1583: // clear sub-state machines martin@1583: ec_fsm_coe_clear(&fsm->fsm_coe); martin@1597: ec_fsm_foe_clear(&fsm->fsm_foe); fp@1831: ec_fsm_soe_clear(&fsm->fsm_soe); fp@2597: ec_fsm_eoe_clear(&fsm->fsm_eoe); martin@1583: } martin@1583: martin@1583: /*****************************************************************************/ martin@1583: martin@1583: /** Executes the current state of the state machine. martin@1583: * fp@2589: * \return 1 if \a datagram was used, else 0. ch1010277@2017: */ ch1010277@2017: int ec_fsm_slave_exec( fp@2589: ec_fsm_slave_t *fsm, /**< Slave state machine. */ fp@2589: ec_datagram_t *datagram /**< New datagram to use. */ fp@2589: ) fp@2589: { fp@2589: int datagram_used; fp@2589: fp@2589: fsm->state(fsm, datagram); fp@2589: fp@2589: datagram_used = fsm->state != ec_fsm_slave_state_idle && fp@2589: fsm->state != ec_fsm_slave_state_ready; fp@2589: fp@2589: if (datagram_used) { fp@2589: fsm->datagram = datagram; fp@2589: } else { fp@2589: fsm->datagram = NULL; fp@2589: } fp@2589: fp@2589: return datagram_used; martin@1583: } martin@1583: martin@1601: /*****************************************************************************/ martin@1601: martin@1601: /** Sets the current state of the state machine to READY martin@1601: */ fp@2589: void ec_fsm_slave_set_ready( fp@1804: ec_fsm_slave_t *fsm /**< Slave state machine. */ fp@1804: ) fp@1804: { fp@1804: if (fsm->state == ec_fsm_slave_state_idle) { fp@1921: EC_SLAVE_DBG(fsm->slave, 1, "Ready for requests.\n"); fp@1804: fsm->state = ec_fsm_slave_state_ready; fp@1804: } martin@1601: } martin@1601: fp@2589: /*****************************************************************************/ fp@2589: fp@2589: /** Returns, if the FSM is currently not busy and ready to execute. fp@2589: * fp@2589: * \return Non-zero if ready. fp@2589: */ fp@2589: int ec_fsm_slave_is_ready( fp@2589: const ec_fsm_slave_t *fsm /**< Slave state machine. */ fp@2589: ) fp@2589: { fp@2589: return fsm->state == ec_fsm_slave_state_ready; fp@2589: } fp@2589: martin@1583: /****************************************************************************** martin@1583: * Slave state machine martin@1583: *****************************************************************************/ martin@1583: martin@1583: /** Slave state: IDLE. martin@1583: */ martin@1583: void ec_fsm_slave_state_idle( fp@2589: ec_fsm_slave_t *fsm, /**< Slave state machine. */ fp@2589: ec_datagram_t *datagram /**< Datagram to use. */ fp@1804: ) fp@1804: { fp@1804: // do nothing martin@1601: } martin@1601: martin@1601: /*****************************************************************************/ martin@1601: martin@1601: /** Slave state: READY. martin@1601: */ martin@1601: void ec_fsm_slave_state_ready( fp@2589: ec_fsm_slave_t *fsm, /**< Slave state machine. */ fp@2589: ec_datagram_t *datagram /**< Datagram to use. */ fp@1804: ) fp@1804: { kba@2629: ec_slave_t *slave = fsm->slave; kba@2629: ec_sdo_request_t *req; kba@2629: kba@2629: if (slave->config) { kba@2629: list_for_each_entry(req, &slave->config->sdo_requests, list) { kba@2629: if (req->state == EC_INT_REQUEST_QUEUED || req->state == EC_INT_REQUEST_BUSY) { kba@2629: EC_SLAVE_DBG(slave, 1, "Busy - processing internal SDO request!\n"); kba@2629: return; kba@2629: } kba@2629: } kba@2629: } kba@2629: fp@1804: // Check for pending external SDO requests fp@2589: if (ec_fsm_slave_action_process_sdo(fsm, datagram)) { fp@2589: return; fp@2589: } fp@2589: fp@2589: // Check for pending external register requests fp@2589: if (ec_fsm_slave_action_process_reg(fsm, datagram)) { fp@2589: return; fp@2589: } fp@1804: fp@1831: // Check for pending FoE requests fp@2589: if (ec_fsm_slave_action_process_foe(fsm, datagram)) { fp@2589: return; fp@2589: } fp@1831: fp@1831: // Check for pending SoE requests fp@2589: if (ec_fsm_slave_action_process_soe(fsm, datagram)) { fp@2589: return; fp@2589: } fp@2597: fp@2597: // Check for pending EoE IP parameter requests fp@2597: if (ec_fsm_slave_action_process_eoe(fsm, datagram)) { fp@2597: return; fp@2597: } fp@1804: } martin@1597: martin@1597: /*****************************************************************************/ martin@1597: martin@1597: /** Check for pending SDO requests and process one. martin@1597: * martin@1597: * \return non-zero, if an SDO request is processed. martin@1597: */ martin@1597: int ec_fsm_slave_action_process_sdo( fp@2589: ec_fsm_slave_t *fsm, /**< Slave state machine. */ fp@2589: ec_datagram_t *datagram /**< Datagram to use. */ fp@2589: ) fp@2589: { fp@2589: ec_slave_t *slave = fsm->slave; fp@2589: ec_sdo_request_t *request; fp@2589: fp@2589: if (list_empty(&slave->sdo_requests)) { fp@2589: return 0; fp@2589: } fp@2589: fp@2589: // take the first request to be processed fp@2589: request = list_entry(slave->sdo_requests.next, ec_sdo_request_t, list); fp@2589: list_del_init(&request->list); // dequeue fp@2589: fp@2589: if (slave->current_state & EC_SLAVE_STATE_ACK_ERR) { fp@2589: EC_SLAVE_WARN(slave, "Aborting SDO request," fp@2589: " slave has error flag set.\n"); fp@2589: request->state = EC_INT_REQUEST_FAILURE; fp@2589: wake_up_all(&slave->master->request_queue); fp@2589: fsm->state = ec_fsm_slave_state_idle; fp@2597: return 0; martin@1597: } fp@2589: fp@2589: if (slave->current_state == EC_SLAVE_STATE_INIT) { fp@2589: EC_SLAVE_WARN(slave, "Aborting SDO request, slave is in INIT.\n"); fp@2589: request->state = EC_INT_REQUEST_FAILURE; fp@2589: wake_up_all(&slave->master->request_queue); fp@2589: fsm->state = ec_fsm_slave_state_idle; fp@2597: return 0; fp@2589: } fp@2589: fp@2589: fsm->sdo_request = request; fp@2589: request->state = EC_INT_REQUEST_BUSY; fp@2589: fp@2589: // Found pending SDO request. Execute it! fp@2589: EC_SLAVE_DBG(slave, 1, "Processing SDO request...\n"); fp@2589: fp@2589: // Start SDO transfer fp@2589: fsm->state = ec_fsm_slave_state_sdo_request; fp@2589: ec_fsm_coe_transfer(&fsm->fsm_coe, slave, request); fp@2589: ec_fsm_coe_exec(&fsm->fsm_coe, datagram); // execute immediately fp@2589: return 1; martin@1597: } martin@1597: martin@1583: /*****************************************************************************/ martin@1583: martin@1583: /** Slave state: SDO_REQUEST. martin@1583: */ martin@1583: void ec_fsm_slave_state_sdo_request( fp@2589: ec_fsm_slave_t *fsm, /**< Slave state machine. */ fp@2589: ec_datagram_t *datagram /**< Datagram to use. */ fp@2589: ) fp@2589: { fp@2589: ec_slave_t *slave = fsm->slave; fp@2589: ec_sdo_request_t *request = fsm->sdo_request; fp@2589: fp@2589: if (ec_fsm_coe_exec(&fsm->fsm_coe, datagram)) { fp@2589: return; fp@2589: } fp@2589: martin@1583: if (!ec_fsm_coe_success(&fsm->fsm_coe)) { fp@2589: EC_SLAVE_ERR(slave, "Failed to process SDO request.\n"); fp@2589: request->state = EC_INT_REQUEST_FAILURE; fp@2589: wake_up_all(&slave->master->request_queue); fp@1804: fsm->sdo_request = NULL; fp@2589: fsm->state = ec_fsm_slave_state_ready; fp@2589: return; fp@2589: } fp@2589: fp@2589: EC_SLAVE_DBG(slave, 1, "Finished SDO request.\n"); martin@1597: martin@1583: // SDO request finished fp@2589: request->state = EC_INT_REQUEST_SUCCESS; fp@2589: wake_up_all(&slave->master->request_queue); martin@1597: fsm->sdo_request = NULL; fp@1804: fsm->state = ec_fsm_slave_state_ready; fp@1804: } martin@1597: martin@1597: /*****************************************************************************/ martin@1597: fp@2589: /** Check for pending register requests and process one. fp@2589: * fp@2589: * \return non-zero, if a register request is processed. fp@2589: */ fp@2589: int ec_fsm_slave_action_process_reg( fp@2589: ec_fsm_slave_t *fsm, /**< Slave state machine. */ fp@2589: ec_datagram_t *datagram /**< Datagram to use. */ fp@2589: ) fp@2589: { fp@2589: ec_slave_t *slave = fsm->slave; fp@2589: ec_reg_request_t *reg; fp@2589: fp@2589: fsm->reg_request = NULL; fp@2589: fp@2589: if (slave->config) { fp@2589: // search the first internal register request to be processed fp@2589: list_for_each_entry(reg, &slave->config->reg_requests, list) { fp@2589: if (reg->state == EC_INT_REQUEST_QUEUED) { fp@2589: fsm->reg_request = reg; fp@2589: break; fp@2589: } fp@2589: } fp@2589: } fp@2589: fp@2589: if (!fsm->reg_request && !list_empty(&slave->reg_requests)) { fp@2589: // take the first external request to be processed fp@2589: fsm->reg_request = fp@2589: list_entry(slave->reg_requests.next, ec_reg_request_t, list); fp@2589: list_del_init(&fsm->reg_request->list); // dequeue fp@2589: } fp@2589: fp@2589: if (!fsm->reg_request) { // no register request to process fp@2589: return 0; fp@2589: } fp@2589: fp@2589: if (slave->current_state & EC_SLAVE_STATE_ACK_ERR) { fp@2589: EC_SLAVE_WARN(slave, "Aborting register request," fp@2589: " slave has error flag set.\n"); fp@2589: fsm->reg_request->state = EC_INT_REQUEST_FAILURE; fp@2589: wake_up_all(&slave->master->request_queue); fp@2589: fsm->reg_request = NULL; fp@2589: fsm->state = ec_fsm_slave_state_idle; fp@2597: return 0; fp@2589: } fp@2589: fp@2589: // Found pending register request. Execute it! fp@2589: EC_SLAVE_DBG(slave, 1, "Processing register request...\n"); fp@2589: fp@2589: fsm->reg_request->state = EC_INT_REQUEST_BUSY; fp@2589: fp@2589: // Start register access fp@2589: if (fsm->reg_request->dir == EC_DIR_INPUT) { fp@2589: ec_datagram_fprd(datagram, slave->station_address, fp@2589: fsm->reg_request->address, fsm->reg_request->transfer_size); fp@2589: ec_datagram_zero(datagram); fp@2589: } else { fp@2589: ec_datagram_fpwr(datagram, slave->station_address, fp@2589: fsm->reg_request->address, fsm->reg_request->transfer_size); fp@2589: memcpy(datagram->data, fsm->reg_request->data, fp@2589: fsm->reg_request->transfer_size); fp@2589: } fp@2589: datagram->device_index = slave->device_index; fp@2589: fsm->state = ec_fsm_slave_state_reg_request; fp@2589: return 1; fp@2589: } fp@2589: fp@2589: /*****************************************************************************/ fp@2589: fp@2589: /** Slave state: Register request. fp@2589: */ fp@2589: void ec_fsm_slave_state_reg_request( fp@2589: ec_fsm_slave_t *fsm, /**< Slave state machine. */ fp@2589: ec_datagram_t *datagram /**< Datagram to use. */ fp@2589: ) fp@2589: { fp@2589: ec_slave_t *slave = fsm->slave; fp@2589: ec_reg_request_t *reg = fsm->reg_request; fp@2589: fp@2589: if (!reg) { fp@2589: // configuration was cleared in the meantime fp@2589: fsm->state = ec_fsm_slave_state_ready; fp@2589: fsm->reg_request = NULL; fp@2589: return; fp@2589: } fp@2589: fp@2589: if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) { fp@2589: EC_SLAVE_ERR(slave, "Failed to receive register" fp@2589: " request datagram: "); fp@2589: ec_datagram_print_state(fsm->datagram); fp@2589: reg->state = EC_INT_REQUEST_FAILURE; fp@2589: wake_up_all(&slave->master->request_queue); fp@2589: fsm->reg_request = NULL; fp@2589: fsm->state = ec_fsm_slave_state_ready; fp@2589: return; fp@2589: } fp@2589: fp@2589: if (fsm->datagram->working_counter == 1) { fp@2589: if (reg->dir == EC_DIR_INPUT) { // read request fp@2589: memcpy(reg->data, fsm->datagram->data, reg->transfer_size); fp@2589: } fp@2589: fp@2589: reg->state = EC_INT_REQUEST_SUCCESS; fp@2589: EC_SLAVE_DBG(slave, 1, "Register request successful.\n"); fp@2589: } else { fp@2589: reg->state = EC_INT_REQUEST_FAILURE; fp@2589: ec_datagram_print_state(fsm->datagram); fp@2589: EC_SLAVE_ERR(slave, "Register request failed" fp@2589: " (working counter is %u).\n", fp@2589: fsm->datagram->working_counter); fp@2589: } fp@2589: fp@2589: wake_up_all(&slave->master->request_queue); fp@2589: fsm->reg_request = NULL; fp@2589: fsm->state = ec_fsm_slave_state_ready; fp@2589: } fp@2589: fp@2589: /*****************************************************************************/ fp@2589: fp@2589: /** Check for pending FoE requests and process one. fp@2589: * fp@2589: * \return non-zero, if an FoE request is processed. fp@1831: */ fp@1831: int ec_fsm_slave_action_process_foe( fp@2589: ec_fsm_slave_t *fsm, /**< Slave state machine. */ fp@2589: ec_datagram_t *datagram /**< Datagram to use. */ fp@2589: ) fp@2589: { fp@2589: ec_slave_t *slave = fsm->slave; fp@2589: ec_foe_request_t *request; fp@2589: fp@2589: if (list_empty(&slave->foe_requests)) { fp@2589: return 0; fp@2589: } fp@2589: fp@2589: // take the first request to be processed fp@2589: request = list_entry(slave->foe_requests.next, ec_foe_request_t, list); fp@2589: list_del_init(&request->list); // dequeue fp@2589: fp@2589: if (slave->current_state & EC_SLAVE_STATE_ACK_ERR) { fp@2589: EC_SLAVE_WARN(slave, "Aborting FoE request," fp@2589: " slave has error flag set.\n"); fp@2589: request->state = EC_INT_REQUEST_FAILURE; fp@2589: wake_up_all(&slave->master->request_queue); fp@2589: fsm->state = ec_fsm_slave_state_idle; fp@2597: return 0; fp@1831: } fp@2589: fp@2589: request->state = EC_INT_REQUEST_BUSY; fp@2589: fsm->foe_request = request; fp@2589: fp@2589: EC_SLAVE_DBG(slave, 1, "Processing FoE request.\n"); fp@2589: fp@2589: fsm->state = ec_fsm_slave_state_foe_request; fp@2589: ec_fsm_foe_transfer(&fsm->fsm_foe, slave, request); fp@2589: ec_fsm_foe_exec(&fsm->fsm_foe, datagram); fp@2589: return 1; fp@1831: } fp@1831: fp@1831: /*****************************************************************************/ fp@1831: martin@1597: /** Slave state: FOE REQUEST. martin@1597: */ martin@1597: void ec_fsm_slave_state_foe_request( fp@2589: ec_fsm_slave_t *fsm, /**< Slave state machine. */ fp@2589: ec_datagram_t *datagram /**< Datagram to use. */ fp@2589: ) fp@2589: { fp@2589: ec_slave_t *slave = fsm->slave; fp@2589: ec_foe_request_t *request = fsm->foe_request; fp@2589: fp@2589: if (ec_fsm_foe_exec(&fsm->fsm_foe, datagram)) { martin@1597: return; martin@1597: } martin@1597: martin@1597: if (!ec_fsm_foe_success(&fsm->fsm_foe)) { fp@2589: EC_SLAVE_ERR(slave, "Failed to handle FoE request.\n"); fp@2589: request->state = EC_INT_REQUEST_FAILURE; fp@2589: wake_up_all(&slave->master->request_queue); martin@1597: fsm->foe_request = NULL; fp@2589: fsm->state = ec_fsm_slave_state_ready; martin@1597: return; martin@1597: } martin@1597: martin@1597: // finished transferring FoE fp@2589: EC_SLAVE_DBG(slave, 1, "Successfully transferred %zu bytes of FoE" fp@2589: " data.\n", request->data_size); fp@2589: fp@2589: request->state = EC_INT_REQUEST_SUCCESS; fp@2589: wake_up_all(&slave->master->request_queue); martin@1597: fsm->foe_request = NULL; fp@1804: fsm->state = ec_fsm_slave_state_ready; fp@1804: } fp@1804: fp@1804: /*****************************************************************************/ fp@1831: fp@1831: /** Check for pending SoE requests and process one. fp@1831: * fp@1831: * \return non-zero, if a request is processed. fp@1831: */ fp@1831: int ec_fsm_slave_action_process_soe( fp@2589: ec_fsm_slave_t *fsm, /**< Slave state machine. */ fp@2589: ec_datagram_t *datagram /**< Datagram to use. */ fp@2589: ) fp@2589: { fp@2589: ec_slave_t *slave = fsm->slave; fp@2589: ec_soe_request_t *req; fp@2589: fp@2589: if (list_empty(&slave->soe_requests)) { fp@2589: return 0; fp@2589: } fp@2589: fp@2589: // take the first request to be processed fp@2589: req = list_entry(slave->soe_requests.next, ec_soe_request_t, list); fp@2589: list_del_init(&req->list); // dequeue fp@2589: fp@2589: if (slave->current_state & EC_SLAVE_STATE_ACK_ERR) { fp@2589: EC_SLAVE_WARN(slave, "Aborting SoE request," fp@2589: " slave has error flag set.\n"); fp@2589: req->state = EC_INT_REQUEST_FAILURE; fp@2589: wake_up_all(&slave->master->request_queue); fp@2589: fsm->state = ec_fsm_slave_state_idle; fp@2597: return 0; fp@1831: } fp@2589: fp@2589: if (slave->current_state == EC_SLAVE_STATE_INIT) { fp@2589: EC_SLAVE_WARN(slave, "Aborting SoE request, slave is in INIT.\n"); fp@2589: req->state = EC_INT_REQUEST_FAILURE; fp@2589: wake_up_all(&slave->master->request_queue); fp@2589: fsm->state = ec_fsm_slave_state_idle; fp@2589: return 0; fp@2589: } fp@2589: fp@2589: fsm->soe_request = req; fp@2589: req->state = EC_INT_REQUEST_BUSY; fp@2589: fp@2589: // Found pending request. Execute it! fp@2589: EC_SLAVE_DBG(slave, 1, "Processing SoE request...\n"); fp@2589: fp@2589: // Start SoE transfer fp@2589: fsm->state = ec_fsm_slave_state_soe_request; fp@2589: ec_fsm_soe_transfer(&fsm->fsm_soe, slave, req); fp@2589: ec_fsm_soe_exec(&fsm->fsm_soe, datagram); // execute immediately fp@2589: return 1; fp@1831: } fp@1831: fp@1831: /*****************************************************************************/ fp@1831: fp@1831: /** Slave state: SOE_REQUEST. fp@1831: */ fp@1831: void ec_fsm_slave_state_soe_request( fp@2589: ec_fsm_slave_t *fsm, /**< Slave state machine. */ fp@2589: ec_datagram_t *datagram /**< Datagram to use. */ fp@2589: ) fp@2589: { fp@2589: ec_slave_t *slave = fsm->slave; fp@2589: ec_soe_request_t *request = fsm->soe_request; fp@2589: fp@2589: if (ec_fsm_soe_exec(&fsm->fsm_soe, datagram)) { fp@1831: return; fp@1831: } fp@1831: fp@1831: if (!ec_fsm_soe_success(&fsm->fsm_soe)) { fp@1921: EC_SLAVE_ERR(slave, "Failed to process SoE request.\n"); fp@2589: request->state = EC_INT_REQUEST_FAILURE; fp@2589: wake_up_all(&slave->master->request_queue); fp@1831: fsm->soe_request = NULL; fp@2589: fsm->state = ec_fsm_slave_state_ready; fp@1831: return; fp@1831: } fp@1831: fp@1921: EC_SLAVE_DBG(slave, 1, "Finished SoE request.\n"); fp@1831: fp@1831: // SoE request finished fp@2589: request->state = EC_INT_REQUEST_SUCCESS; fp@2589: wake_up_all(&slave->master->request_queue); fp@1831: fsm->soe_request = NULL; fp@1831: fsm->state = ec_fsm_slave_state_ready; fp@1831: } fp@1831: fp@1831: /*****************************************************************************/ fp@2597: fp@2597: /** Check for pending EoE IP parameter requests and process one. fp@2597: * fp@2597: * \return non-zero, if a request is processed. fp@2597: */ fp@2597: int ec_fsm_slave_action_process_eoe( fp@2597: ec_fsm_slave_t *fsm, /**< Slave state machine. */ fp@2597: ec_datagram_t *datagram /**< Datagram to use. */ fp@2597: ) fp@2597: { fp@2597: ec_slave_t *slave = fsm->slave; fp@2597: ec_eoe_request_t *request; fp@2597: fp@2597: if (list_empty(&slave->eoe_requests)) { fp@2597: return 0; fp@2597: } fp@2597: fp@2597: // take the first request to be processed fp@2597: request = list_entry(slave->eoe_requests.next, ec_eoe_request_t, list); fp@2597: list_del_init(&request->list); // dequeue fp@2597: fp@2597: if (slave->current_state & EC_SLAVE_STATE_ACK_ERR) { fp@2597: EC_SLAVE_WARN(slave, "Aborting EoE request," fp@2597: " slave has error flag set.\n"); fp@2597: request->state = EC_INT_REQUEST_FAILURE; fp@2597: wake_up_all(&slave->master->request_queue); fp@2597: fsm->state = ec_fsm_slave_state_idle; fp@2597: return 0; fp@2597: } fp@2597: fp@2597: if (slave->current_state == EC_SLAVE_STATE_INIT) { fp@2597: EC_SLAVE_WARN(slave, "Aborting EoE request, slave is in INIT.\n"); fp@2597: request->state = EC_INT_REQUEST_FAILURE; fp@2597: wake_up_all(&slave->master->request_queue); fp@2597: fsm->state = ec_fsm_slave_state_idle; fp@2597: return 0; fp@2597: } fp@2597: fp@2597: fsm->eoe_request = request; fp@2597: request->state = EC_INT_REQUEST_BUSY; fp@2597: fp@2597: // Found pending request. Execute it! fp@2597: EC_SLAVE_DBG(slave, 1, "Processing EoE request...\n"); fp@2597: fp@2597: // Start EoE command fp@2597: fsm->state = ec_fsm_slave_state_eoe_request; fp@2597: ec_fsm_eoe_set_ip_param(&fsm->fsm_eoe, slave, request); fp@2597: ec_fsm_eoe_exec(&fsm->fsm_eoe, datagram); // execute immediately fp@2597: return 1; fp@2597: } fp@2597: fp@2597: /*****************************************************************************/ fp@2597: fp@2597: /** Slave state: EOE_REQUEST. fp@2597: */ fp@2597: void ec_fsm_slave_state_eoe_request( fp@2597: ec_fsm_slave_t *fsm, /**< Slave state machine. */ fp@2597: ec_datagram_t *datagram /**< Datagram to use. */ fp@2597: ) fp@2597: { fp@2597: ec_slave_t *slave = fsm->slave; fp@2597: ec_eoe_request_t *req = fsm->eoe_request; fp@2597: fp@2597: if (ec_fsm_eoe_exec(&fsm->fsm_eoe, datagram)) { fp@2597: return; fp@2597: } fp@2597: fp@2597: if (ec_fsm_eoe_success(&fsm->fsm_eoe)) { fp@2597: req->state = EC_INT_REQUEST_SUCCESS; fp@2597: EC_SLAVE_DBG(slave, 1, "Finished EoE request.\n"); fp@2597: } fp@2597: else { fp@2597: req->state = EC_INT_REQUEST_FAILURE; fp@2597: EC_SLAVE_ERR(slave, "Failed to process EoE request.\n"); fp@2597: } fp@2597: fp@2597: wake_up_all(&slave->master->request_queue); fp@2597: fsm->eoe_request = NULL; fp@2597: fsm->state = ec_fsm_slave_state_ready; fp@2597: } fp@2597: fp@2597: /*****************************************************************************/