fp@1732: /****************************************************************************** fp@1732: * fp@1732: * $Id$ fp@1732: * fp@1732: * Copyright (C) 2006 Florian Pose, Ingenieurgemeinschaft IgH fp@1732: * fp@1732: * This file is part of the IgH EtherCAT Master. fp@1732: * fp@1732: * The IgH EtherCAT Master is free software; you can redistribute it fp@1732: * and/or modify it under the terms of the GNU General Public License fp@1732: * as published by the Free Software Foundation; either version 2 of the fp@1732: * License, or (at your option) any later version. fp@1732: * fp@1732: * The IgH EtherCAT Master is distributed in the hope that it will be fp@1732: * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of fp@1732: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the fp@1732: * GNU General Public License for more details. fp@1732: * fp@1732: * You should have received a copy of the GNU General Public License fp@1732: * along with the IgH EtherCAT Master; if not, write to the Free Software fp@1732: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA fp@1732: * fp@1732: * The right to use EtherCAT Technology is granted and comes free of fp@1732: * charge under condition of compatibility of product made by fp@1732: * Licensee. People intending to distribute/sell products based on the fp@1732: * code, have to sign an agreement to guarantee that products using fp@1732: * software based on IgH EtherCAT master stay compatible with the actual fp@1732: * EtherCAT specification (which are released themselves as an open fp@1732: * standard) as the (only) precondition to have the right to use EtherCAT fp@1732: * Technology, IP and trade marks. fp@1732: * fp@1732: *****************************************************************************/ fp@1732: fp@1732: /** fp@1732: \file fp@1732: EtherCAT slave information interface FSM. fp@1732: */ fp@1732: fp@1732: /*****************************************************************************/ fp@1732: fp@1732: #include "globals.h" fp@1732: #include "mailbox.h" fp@1732: #include "master.h" fp@1732: #include "fsm_sii.h" fp@1732: fp@1746: /** fp@1746: * Read/Write timeout. [ms] fp@1746: */ fp@1746: #define EEPROM_TIMEOUT 10 fp@1746: fp@1746: /** fp@1746: * Time before evaluating answer at writing. [ms] fp@1746: */ fp@1746: #define EEPROM_INHIBIT 5 fp@1746: fp@1746: //#define SII_DEBUG fp@1746: fp@1746: /*****************************************************************************/ fp@1746: fp@1746: void ec_fsm_sii_state_start_reading(ec_fsm_sii_t *); fp@1746: void ec_fsm_sii_state_read_check(ec_fsm_sii_t *); fp@1746: void ec_fsm_sii_state_read_fetch(ec_fsm_sii_t *); fp@1746: void ec_fsm_sii_state_start_writing(ec_fsm_sii_t *); fp@1746: void ec_fsm_sii_state_write_check(ec_fsm_sii_t *); fp@1746: void ec_fsm_sii_state_write_check2(ec_fsm_sii_t *); fp@1746: void ec_fsm_sii_state_end(ec_fsm_sii_t *); fp@1746: void ec_fsm_sii_state_error(ec_fsm_sii_t *); fp@1732: fp@1732: /*****************************************************************************/ fp@1732: fp@1732: /** fp@1732: Constructor. fp@1732: */ fp@1732: fp@1732: void ec_fsm_sii_init(ec_fsm_sii_t *fsm, /**< finite state machine */ fp@1732: ec_datagram_t *datagram /**< datagram structure to use */ fp@1732: ) fp@1732: { fp@1732: fsm->state = NULL; fp@1732: fsm->datagram = datagram; fp@1732: } fp@1732: fp@1732: /*****************************************************************************/ fp@1732: fp@1732: /** fp@1732: Destructor. fp@1732: */ fp@1732: fp@1732: void ec_fsm_sii_clear(ec_fsm_sii_t *fsm /**< finite state machine */) fp@1732: { fp@1732: } fp@1732: fp@1732: /*****************************************************************************/ fp@1732: fp@1732: /** fp@1732: Initializes the SII read state machine. fp@1732: */ fp@1732: fp@1732: void ec_fsm_sii_read(ec_fsm_sii_t *fsm, /**< finite state machine */ fp@1732: ec_slave_t *slave, /**< slave to read from */ fp@1746: uint16_t word_offset, /**< offset to read from */ fp@1732: ec_fsm_sii_addressing_t mode /**< addressing scheme */ fp@1732: ) fp@1732: { fp@1746: fsm->state = ec_fsm_sii_state_start_reading; fp@1732: fsm->slave = slave; fp@1746: fsm->word_offset = word_offset; fp@1732: fsm->mode = mode; fp@1732: } fp@1732: fp@1732: /*****************************************************************************/ fp@1732: fp@1732: /** fp@1732: Initializes the SII write state machine. fp@1732: */ fp@1732: fp@1732: void ec_fsm_sii_write(ec_fsm_sii_t *fsm, /**< finite state machine */ fp@1732: ec_slave_t *slave, /**< slave to read from */ fp@1746: uint16_t word_offset, /**< offset to read from */ fp@1746: const uint8_t *value, /**< pointer to 2 bytes of data */ fp@1732: ec_fsm_sii_addressing_t mode /**< addressing scheme */ fp@1732: ) fp@1732: { fp@1746: fsm->state = ec_fsm_sii_state_start_writing; fp@1732: fsm->slave = slave; fp@1746: fsm->word_offset = word_offset; fp@1732: fsm->mode = mode; fp@1732: memcpy(fsm->value, value, 2); fp@1732: } fp@1732: fp@1732: /*****************************************************************************/ fp@1732: fp@1732: /** fp@1732: Executes the SII state machine. fp@1732: \return false, if the state machine has terminated fp@1732: */ fp@1732: fp@1732: int ec_fsm_sii_exec(ec_fsm_sii_t *fsm /**< finite state machine */) fp@1732: { fp@1732: fsm->state(fsm); fp@1732: fp@1746: return fsm->state != ec_fsm_sii_state_end fp@1746: && fsm->state != ec_fsm_sii_state_error; fp@1732: } fp@1732: fp@1732: /*****************************************************************************/ fp@1732: fp@1732: /** fp@1732: Returns, if the master startup state machine terminated with success. fp@1732: \return non-zero if successful. fp@1732: */ fp@1732: fp@1732: int ec_fsm_sii_success(ec_fsm_sii_t *fsm /**< Finite state machine */) fp@1732: { fp@1746: return fsm->state == ec_fsm_sii_state_end; fp@1732: } fp@1732: fp@1732: /****************************************************************************** fp@1746: * state functions fp@1732: *****************************************************************************/ fp@1732: fp@1732: /** fp@1732: SII state: START READING. fp@1732: Starts reading the slave information interface. fp@1732: */ fp@1732: fp@1746: void ec_fsm_sii_state_start_reading( fp@1746: ec_fsm_sii_t *fsm /**< finite state machine */ fp@1746: ) fp@1732: { fp@1732: ec_datagram_t *datagram = fsm->datagram; fp@1732: fp@1732: // initiate read operation fp@1732: switch (fsm->mode) { fp@1732: case EC_FSM_SII_POSITION: fp@1732: ec_datagram_apwr(datagram, fsm->slave->ring_position, 0x502, 4); fp@1732: break; fp@1732: case EC_FSM_SII_NODE: fp@1732: ec_datagram_npwr(datagram, fsm->slave->station_address, 0x502, 4); fp@1732: break; fp@1732: } fp@1732: fp@1746: EC_WRITE_U8 (datagram->data, 0x80); // two address octets fp@1732: EC_WRITE_U8 (datagram->data + 1, 0x01); // request read operation fp@1746: EC_WRITE_U16(datagram->data + 2, fsm->word_offset); fp@1746: fp@1746: #ifdef SII_DEBUG fp@1746: EC_DBG("reading SII data:\n"); fp@1746: ec_print_data(datagram->data, 4); fp@1746: #endif fp@1746: fp@1739: fsm->retries = EC_FSM_RETRIES; fp@1746: fsm->state = ec_fsm_sii_state_read_check; fp@1732: } fp@1732: fp@1732: /*****************************************************************************/ fp@1732: fp@1732: /** fp@1732: SII state: READ CHECK. fp@1732: Checks, if the SII-read-datagram has been sent and issues a fetch datagram. fp@1732: */ fp@1732: fp@1746: void ec_fsm_sii_state_read_check( fp@1746: ec_fsm_sii_t *fsm /**< finite state machine */ fp@1746: ) fp@1732: { fp@1732: ec_datagram_t *datagram = fsm->datagram; fp@1732: fp@1744: if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) fp@1744: return; fp@1739: fp@1739: if (datagram->state != EC_DATAGRAM_RECEIVED) { fp@1746: fsm->state = ec_fsm_sii_state_error; fp@1744: EC_ERR("Failed to receive SII read datagram from slave %i" fp@1744: " (datagram state %i).\n", fp@1744: fsm->slave->ring_position, datagram->state); fp@1739: return; fp@1739: } fp@1739: fp@1739: if (datagram->working_counter != 1) { fp@1746: fsm->state = ec_fsm_sii_state_error; fp@1745: EC_ERR("Reception of SII read datagram failed on slave %i: ", fp@1745: fsm->slave->ring_position); fp@1745: ec_datagram_print_wc_error(datagram); fp@1732: return; fp@1732: } fp@1732: fp@1732: fsm->cycles_start = datagram->cycles_sent; fp@1732: fsm->check_once_more = 1; fp@1732: fp@1732: // issue check/fetch datagram fp@1732: switch (fsm->mode) { fp@1732: case EC_FSM_SII_POSITION: fp@1732: ec_datagram_aprd(datagram, fsm->slave->ring_position, 0x502, 10); fp@1732: break; fp@1732: case EC_FSM_SII_NODE: fp@1732: ec_datagram_nprd(datagram, fsm->slave->station_address, 0x502, 10); fp@1732: break; fp@1732: } fp@1744: fp@1739: fsm->retries = EC_FSM_RETRIES; fp@1746: fsm->state = ec_fsm_sii_state_read_fetch; fp@1732: } fp@1732: fp@1732: /*****************************************************************************/ fp@1732: fp@1732: /** fp@1732: SII state: READ FETCH. fp@1732: Fetches the result of an SII-read datagram. fp@1732: */ fp@1732: fp@1746: void ec_fsm_sii_state_read_fetch( fp@1746: ec_fsm_sii_t *fsm /**< finite state machine */ fp@1746: ) fp@1732: { fp@1732: ec_datagram_t *datagram = fsm->datagram; fp@1732: fp@1744: if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) fp@1744: return; fp@1739: fp@1739: if (datagram->state != EC_DATAGRAM_RECEIVED) { fp@1746: fsm->state = ec_fsm_sii_state_error; fp@1744: EC_ERR("Failed to receive SII check/fetch datagram from slave %i" fp@1744: " (datagram state %i).\n", fp@1744: fsm->slave->ring_position, datagram->state); fp@1739: return; fp@1739: } fp@1739: fp@1739: if (datagram->working_counter != 1) { fp@1746: fsm->state = ec_fsm_sii_state_error; fp@1745: EC_ERR("Reception of SII check/fetch datagram failed on slave %i: ", fp@1745: fsm->slave->ring_position); fp@1745: ec_datagram_print_wc_error(datagram); fp@1732: return; fp@1732: } fp@1732: fp@1746: #ifdef SII_DEBUG fp@1746: EC_DBG("checking SII read state:\n"); fp@1746: ec_print_data(datagram->data, 10); fp@1746: #endif fp@1746: fp@1746: if (EC_READ_U8(datagram->data + 1) & 0x20) { fp@1746: EC_ERR("SII: Error on last SII command!\n"); fp@1746: fsm->state = ec_fsm_sii_state_error; fp@1746: return; fp@1746: } fp@1746: fp@1732: // check "busy bit" fp@1746: if (EC_READ_U8(datagram->data + 1) & 0x81) { // busy bit or fp@1746: // read operation busy fp@1732: // still busy... timeout? fp@1732: if (datagram->cycles_received fp@1746: - fsm->cycles_start >= (cycles_t) EEPROM_TIMEOUT * cpu_khz) { fp@1746: if (fsm->check_once_more) { fp@1746: fsm->check_once_more = 0; fp@1746: } else { fp@1732: EC_ERR("SII: Read timeout.\n"); fp@1746: fsm->state = ec_fsm_sii_state_error; fp@1732: return; fp@1732: } fp@1732: } fp@1732: fp@1732: // issue check/fetch datagram again fp@1739: fsm->retries = EC_FSM_RETRIES; fp@1732: return; fp@1732: } fp@1732: fp@1732: // SII value received. fp@1732: memcpy(fsm->value, datagram->data + 6, 4); fp@1746: fsm->state = ec_fsm_sii_state_end; fp@1732: } fp@1732: fp@1732: /*****************************************************************************/ fp@1732: fp@1732: /** fp@1732: SII state: START WRITING. fp@1746: Starts writing a word through the slave information interface. fp@1746: */ fp@1746: fp@1746: void ec_fsm_sii_state_start_writing( fp@1746: ec_fsm_sii_t *fsm /**< finite state machine */ fp@1746: ) fp@1732: { fp@1732: ec_datagram_t *datagram = fsm->datagram; fp@1732: fp@1732: // initiate write operation fp@1732: ec_datagram_npwr(datagram, fsm->slave->station_address, 0x502, 8); fp@1746: EC_WRITE_U8 (datagram->data, 0x81); // two address octets fp@1746: // + enable write access fp@1732: EC_WRITE_U8 (datagram->data + 1, 0x02); // request write operation fp@1746: EC_WRITE_U16(datagram->data + 2, fsm->word_offset); fp@1746: memset(datagram->data + 4, 0x00, 2); fp@1732: memcpy(datagram->data + 6, fsm->value, 2); fp@1744: fp@1746: #ifdef SII_DEBUG fp@1746: EC_DBG("writing SII data:\n"); fp@1746: ec_print_data(datagram->data, 8); fp@1746: #endif fp@1746: fp@1739: fsm->retries = EC_FSM_RETRIES; fp@1746: fsm->state = ec_fsm_sii_state_write_check; fp@1732: } fp@1732: fp@1732: /*****************************************************************************/ fp@1732: fp@1732: /** fp@1732: SII state: WRITE CHECK. fp@1732: */ fp@1732: fp@1746: void ec_fsm_sii_state_write_check( fp@1746: ec_fsm_sii_t *fsm /**< finite state machine */ fp@1746: ) fp@1732: { fp@1732: ec_datagram_t *datagram = fsm->datagram; fp@1732: fp@1744: if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) fp@1744: return; fp@1739: fp@1739: if (datagram->state != EC_DATAGRAM_RECEIVED) { fp@1746: fsm->state = ec_fsm_sii_state_error; fp@1744: EC_ERR("Failed to receive SII write datagram for slave %i" fp@1744: " (datagram state %i).\n", fp@1744: fsm->slave->ring_position, datagram->state); fp@1739: return; fp@1739: } fp@1739: fp@1739: if (datagram->working_counter != 1) { fp@1746: fsm->state = ec_fsm_sii_state_error; fp@1745: EC_ERR("Reception of SII write datagram failed on slave %i: ", fp@1745: fsm->slave->ring_position); fp@1745: ec_datagram_print_wc_error(datagram); fp@1732: return; fp@1732: } fp@1732: fp@1732: fsm->cycles_start = datagram->cycles_sent; fp@1732: fsm->check_once_more = 1; fp@1732: fp@1746: // issue check datagram fp@1732: ec_datagram_nprd(datagram, fsm->slave->station_address, 0x502, 2); fp@1739: fsm->retries = EC_FSM_RETRIES; fp@1746: fsm->state = ec_fsm_sii_state_write_check2; fp@1732: } fp@1732: fp@1732: /*****************************************************************************/ fp@1732: fp@1732: /** fp@1732: SII state: WRITE CHECK 2. fp@1732: */ fp@1732: fp@1746: void ec_fsm_sii_state_write_check2( fp@1746: ec_fsm_sii_t *fsm /**< finite state machine */ fp@1746: ) fp@1732: { fp@1732: ec_datagram_t *datagram = fsm->datagram; fp@1732: fp@1744: if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) fp@1744: return; fp@1739: fp@1739: if (datagram->state != EC_DATAGRAM_RECEIVED) { fp@1746: fsm->state = ec_fsm_sii_state_error; fp@1744: EC_ERR("Failed to receive SII write check datagram from slave %i" fp@1744: " (datagram state %i).\n", fp@1744: fsm->slave->ring_position, datagram->state); fp@1739: return; fp@1739: } fp@1739: fp@1739: if (datagram->working_counter != 1) { fp@1746: fsm->state = ec_fsm_sii_state_error; fp@1745: EC_ERR("Reception of SII write check datagram failed on slave %i: ", fp@1745: fsm->slave->ring_position); fp@1745: ec_datagram_print_wc_error(datagram); fp@1732: return; fp@1732: } fp@1732: fp@1746: #ifdef SII_DEBUG fp@1746: EC_DBG("checking SII write state:\n"); fp@1746: ec_print_data(datagram->data, 2); fp@1746: #endif fp@1746: fp@1746: if (EC_READ_U8(datagram->data + 1) & 0x20) { fp@1746: EC_ERR("SII: Error on last SII command!\n"); fp@1746: fsm->state = ec_fsm_sii_state_error; fp@1746: return; fp@1746: } fp@1746: fp@1746: /* FIXME: some slaves never answer with the busy flag set... fp@1746: * wait a few ms for the write operation to complete. */ fp@1746: if (datagram->cycles_received - fsm->cycles_start fp@1746: < (cycles_t) EEPROM_INHIBIT * cpu_khz) { fp@1746: #ifdef SII_DEBUG fp@1746: EC_DBG("too early.\n"); fp@1746: #endif fp@1746: // issue check datagram again fp@1746: fsm->retries = EC_FSM_RETRIES; fp@1746: return; fp@1746: } fp@1746: fp@1746: if (EC_READ_U8(datagram->data + 1) & 0x82) { // busy bit or fp@1746: // write operation busy bit fp@1732: // still busy... timeout? fp@1732: if (datagram->cycles_received fp@1746: - fsm->cycles_start >= (cycles_t) EEPROM_TIMEOUT * cpu_khz) { fp@1746: if (fsm->check_once_more) { fp@1746: fsm->check_once_more = 0; fp@1746: } else { fp@1732: EC_ERR("SII: Write timeout.\n"); fp@1746: fsm->state = ec_fsm_sii_state_error; fp@1732: return; fp@1732: } fp@1732: } fp@1732: fp@1746: // issue check datagram again fp@1739: fsm->retries = EC_FSM_RETRIES; fp@1732: return; fp@1732: } fp@1732: fp@1732: if (EC_READ_U8(datagram->data + 1) & 0x40) { fp@1732: EC_ERR("SII: Write operation failed!\n"); fp@1746: fsm->state = ec_fsm_sii_state_error; fp@1732: return; fp@1732: } fp@1732: fp@1732: // success fp@1746: fsm->state = ec_fsm_sii_state_end; fp@1732: } fp@1732: fp@1732: /*****************************************************************************/ fp@1732: fp@1732: /** fp@1732: State: ERROR. fp@1732: */ fp@1732: fp@1746: void ec_fsm_sii_state_error( fp@1746: ec_fsm_sii_t *fsm /**< finite state machine */ fp@1746: ) fp@1732: { fp@1732: } fp@1732: fp@1732: /*****************************************************************************/ fp@1732: fp@1732: /** fp@1732: State: END. fp@1732: */ fp@1732: fp@1746: void ec_fsm_sii_state_end( fp@1746: ec_fsm_sii_t *fsm /**< finite state machine */ fp@1746: ) fp@1746: { fp@1746: } fp@1746: fp@1746: /*****************************************************************************/