fp@433: /****************************************************************************** fp@433: * fp@433: * $Id$ fp@433: * fp@1326: * Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH fp@433: * fp@433: * This file is part of the IgH EtherCAT Master. fp@433: * 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@433: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA fp@433: * 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@433: * fp@433: *****************************************************************************/ fp@433: fp@433: /** fp@433: \file fp@433: EtherCAT slave information interface FSM. fp@433: */ fp@433: fp@433: /*****************************************************************************/ fp@433: fp@433: #include "globals.h" fp@433: #include "mailbox.h" fp@433: #include "master.h" fp@433: #include "fsm_sii.h" fp@433: fp@1123: /** Read/write timeout [ms]. fp@1123: * fp@1123: * Used to calculate timeouts bsed on the jiffies counter. fp@1123: * fp@1123: * \attention Must be more than 10 to avoid problems on kernels that run with fp@1123: * a timer interupt frequency of 100 Hz. fp@758: */ fp@1123: #define SII_TIMEOUT 20 fp@1123: fp@1123: /** Time before evaluating answer at writing [ms]. fp@758: */ fp@1123: #define SII_INHIBIT 5 fp@755: fp@755: //#define SII_DEBUG fp@755: fp@433: /*****************************************************************************/ fp@433: fp@753: void ec_fsm_sii_state_start_reading(ec_fsm_sii_t *); fp@753: void ec_fsm_sii_state_read_check(ec_fsm_sii_t *); fp@753: void ec_fsm_sii_state_read_fetch(ec_fsm_sii_t *); fp@753: void ec_fsm_sii_state_start_writing(ec_fsm_sii_t *); fp@753: void ec_fsm_sii_state_write_check(ec_fsm_sii_t *); fp@753: void ec_fsm_sii_state_write_check2(ec_fsm_sii_t *); fp@753: void ec_fsm_sii_state_end(ec_fsm_sii_t *); fp@753: void ec_fsm_sii_state_error(ec_fsm_sii_t *); fp@433: fp@433: /*****************************************************************************/ fp@433: fp@433: /** fp@433: Constructor. fp@433: */ fp@433: fp@433: void ec_fsm_sii_init(ec_fsm_sii_t *fsm, /**< finite state machine */ fp@433: ec_datagram_t *datagram /**< datagram structure to use */ fp@433: ) fp@433: { fp@433: fsm->state = NULL; fp@433: fsm->datagram = datagram; fp@433: } fp@433: fp@433: /*****************************************************************************/ fp@433: fp@433: /** fp@433: Destructor. fp@433: */ fp@433: fp@433: void ec_fsm_sii_clear(ec_fsm_sii_t *fsm /**< finite state machine */) fp@433: { fp@433: } fp@433: fp@433: /*****************************************************************************/ fp@433: fp@433: /** fp@433: Initializes the SII read state machine. fp@433: */ fp@433: fp@433: void ec_fsm_sii_read(ec_fsm_sii_t *fsm, /**< finite state machine */ fp@433: ec_slave_t *slave, /**< slave to read from */ fp@755: uint16_t word_offset, /**< offset to read from */ fp@433: ec_fsm_sii_addressing_t mode /**< addressing scheme */ fp@433: ) fp@433: { fp@753: fsm->state = ec_fsm_sii_state_start_reading; fp@433: fsm->slave = slave; fp@755: fsm->word_offset = word_offset; fp@433: fsm->mode = mode; fp@433: } fp@433: fp@433: /*****************************************************************************/ fp@433: fp@433: /** fp@433: Initializes the SII write state machine. fp@433: */ fp@433: fp@433: void ec_fsm_sii_write(ec_fsm_sii_t *fsm, /**< finite state machine */ fp@433: ec_slave_t *slave, /**< slave to read from */ fp@755: uint16_t word_offset, /**< offset to read from */ fp@979: const uint16_t *value, /**< pointer to 2 bytes of data */ fp@433: ec_fsm_sii_addressing_t mode /**< addressing scheme */ fp@433: ) fp@433: { fp@753: fsm->state = ec_fsm_sii_state_start_writing; fp@433: fsm->slave = slave; fp@755: fsm->word_offset = word_offset; fp@433: fsm->mode = mode; fp@433: memcpy(fsm->value, value, 2); fp@433: } fp@433: fp@433: /*****************************************************************************/ fp@433: fp@433: /** fp@433: Executes the SII state machine. fp@435: \return false, if the state machine has terminated fp@435: */ fp@435: fp@435: int ec_fsm_sii_exec(ec_fsm_sii_t *fsm /**< finite state machine */) fp@433: { fp@433: fsm->state(fsm); fp@435: fp@754: return fsm->state != ec_fsm_sii_state_end fp@1507: && fsm->state != ec_fsm_sii_state_error; fp@433: } fp@433: fp@433: /*****************************************************************************/ fp@433: fp@433: /** fp@433: Returns, if the master startup state machine terminated with success. fp@433: \return non-zero if successful. fp@433: */ fp@433: fp@433: int ec_fsm_sii_success(ec_fsm_sii_t *fsm /**< Finite state machine */) fp@433: { fp@753: return fsm->state == ec_fsm_sii_state_end; fp@433: } fp@433: fp@433: /****************************************************************************** fp@754: * state functions fp@433: *****************************************************************************/ fp@433: fp@433: /** fp@433: SII state: START READING. fp@433: Starts reading the slave information interface. fp@433: */ fp@433: fp@754: void ec_fsm_sii_state_start_reading( fp@1507: ec_fsm_sii_t *fsm /**< finite state machine */ fp@1507: ) fp@433: { fp@433: ec_datagram_t *datagram = fsm->datagram; fp@433: fp@433: // initiate read operation fp@433: switch (fsm->mode) { fp@815: case EC_FSM_SII_USE_INCREMENT_ADDRESS: fp@433: ec_datagram_apwr(datagram, fsm->slave->ring_position, 0x502, 4); fp@433: break; fp@815: case EC_FSM_SII_USE_CONFIGURED_ADDRESS: fp@815: ec_datagram_fpwr(datagram, fsm->slave->station_address, 0x502, 4); fp@433: break; fp@433: } fp@433: fp@755: EC_WRITE_U8 (datagram->data, 0x80); // two address octets fp@433: EC_WRITE_U8 (datagram->data + 1, 0x01); // request read operation fp@755: EC_WRITE_U16(datagram->data + 2, fsm->word_offset); fp@755: fp@755: #ifdef SII_DEBUG fp@1957: EC_SLAVE_DBG(fsm->slave, 0, "reading SII data, word %u:\n", fp@1957: fsm->word_offset); fp@1507: ec_print_data(datagram->data, 4); fp@755: #endif fp@755: fp@505: fsm->retries = EC_FSM_RETRIES; fp@753: fsm->state = ec_fsm_sii_state_read_check; fp@433: } fp@433: fp@433: /*****************************************************************************/ fp@433: fp@433: /** fp@433: SII state: READ CHECK. fp@433: Checks, if the SII-read-datagram has been sent and issues a fetch datagram. fp@433: */ fp@433: fp@754: void ec_fsm_sii_state_read_check( fp@1507: ec_fsm_sii_t *fsm /**< finite state machine */ fp@1507: ) fp@433: { fp@433: ec_datagram_t *datagram = fsm->datagram; fp@433: fp@637: if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) fp@637: return; fp@505: fp@505: if (datagram->state != EC_DATAGRAM_RECEIVED) { fp@753: fsm->state = ec_fsm_sii_state_error; fp@1921: EC_SLAVE_ERR(fsm->slave, "Failed to receive SII read datagram: "); fp@1822: ec_datagram_print_state(datagram); fp@505: return; fp@505: } fp@505: fp@505: if (datagram->working_counter != 1) { fp@753: fsm->state = ec_fsm_sii_state_error; fp@1921: EC_SLAVE_ERR(fsm->slave, "Reception of SII read datagram failed: "); fp@713: ec_datagram_print_wc_error(datagram); fp@433: return; fp@433: } fp@433: fp@1039: fsm->jiffies_start = datagram->jiffies_sent; fp@433: fsm->check_once_more = 1; fp@433: fp@433: // issue check/fetch datagram fp@433: switch (fsm->mode) { fp@815: case EC_FSM_SII_USE_INCREMENT_ADDRESS: fp@433: ec_datagram_aprd(datagram, fsm->slave->ring_position, 0x502, 10); fp@433: break; fp@815: case EC_FSM_SII_USE_CONFIGURED_ADDRESS: fp@815: ec_datagram_fprd(datagram, fsm->slave->station_address, 0x502, 10); fp@433: break; fp@433: } fp@637: fp@1225: ec_datagram_zero(datagram); fp@505: fsm->retries = EC_FSM_RETRIES; fp@753: fsm->state = ec_fsm_sii_state_read_fetch; fp@433: } fp@433: fp@433: /*****************************************************************************/ fp@433: fp@433: /** fp@433: SII state: READ FETCH. fp@433: Fetches the result of an SII-read datagram. fp@433: */ fp@754: void ec_fsm_sii_state_read_fetch( fp@1507: ec_fsm_sii_t *fsm /**< finite state machine */ fp@1507: ) fp@433: { fp@433: ec_datagram_t *datagram = fsm->datagram; fp@433: fp@637: if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) fp@637: return; fp@505: fp@505: if (datagram->state != EC_DATAGRAM_RECEIVED) { fp@753: fsm->state = ec_fsm_sii_state_error; fp@1921: EC_SLAVE_ERR(fsm->slave, fp@1921: "Failed to receive SII check/fetch datagram: "); fp@1822: ec_datagram_print_state(datagram); fp@505: return; fp@505: } fp@505: fp@505: if (datagram->working_counter != 1) { fp@753: fsm->state = ec_fsm_sii_state_error; fp@1921: EC_SLAVE_ERR(fsm->slave, fp@1921: "Reception of SII check/fetch datagram failed: "); fp@713: ec_datagram_print_wc_error(datagram); fp@433: return; fp@433: } fp@433: fp@755: #ifdef SII_DEBUG fp@1921: EC_SLAVE_DBG(fsm->slave, 0, "checking SII read state:\n"); fp@1507: ec_print_data(datagram->data, 10); fp@755: #endif fp@755: fp@755: if (EC_READ_U8(datagram->data + 1) & 0x20) { fp@1951: EC_SLAVE_ERR(fsm->slave, "Error on last command while" fp@1951: " reading from SII word 0x%04x.\n", fsm->word_offset); fp@755: fsm->state = ec_fsm_sii_state_error; fp@755: return; fp@755: } fp@755: fp@433: // check "busy bit" fp@1507: if (EC_READ_U8(datagram->data + 1) & 0x81) { /* busy bit or fp@1507: read operation busy */ fp@433: // still busy... timeout? fp@1039: unsigned long diff_ms = fp@1039: (datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ; fp@1039: if (diff_ms >= SII_TIMEOUT) { fp@755: if (fsm->check_once_more) { fp@1507: fsm->check_once_more = 0; fp@1507: } else { fp@1921: EC_SLAVE_ERR(fsm->slave, "SII: Read timeout.\n"); fp@753: fsm->state = ec_fsm_sii_state_error; fp@433: return; fp@433: } fp@433: } fp@433: fp@433: // issue check/fetch datagram again fp@505: fsm->retries = EC_FSM_RETRIES; fp@433: return; fp@433: } fp@433: fp@433: // SII value received. fp@433: memcpy(fsm->value, datagram->data + 6, 4); fp@753: fsm->state = ec_fsm_sii_state_end; fp@433: } fp@433: fp@433: /*****************************************************************************/ fp@433: fp@433: /** fp@433: SII state: START WRITING. fp@755: Starts writing a word through the slave information interface. fp@433: */ fp@433: fp@754: void ec_fsm_sii_state_start_writing( fp@1507: ec_fsm_sii_t *fsm /**< finite state machine */ fp@1507: ) fp@433: { fp@433: ec_datagram_t *datagram = fsm->datagram; fp@433: fp@433: // initiate write operation fp@815: ec_datagram_fpwr(datagram, fsm->slave->station_address, 0x502, 8); fp@1507: EC_WRITE_U8 (datagram->data, 0x81); /* two address octets fp@1507: + enable write access */ fp@433: EC_WRITE_U8 (datagram->data + 1, 0x02); // request write operation fp@755: EC_WRITE_U16(datagram->data + 2, fsm->word_offset); fp@1507: memset(datagram->data + 4, 0x00, 2); fp@433: memcpy(datagram->data + 6, fsm->value, 2); fp@637: fp@755: #ifdef SII_DEBUG fp@1921: EC_SLAVE_DBG(fsm->slave, 0, "writing SII data:\n"); fp@1507: ec_print_data(datagram->data, 8); fp@755: #endif fp@755: fp@505: fsm->retries = EC_FSM_RETRIES; fp@753: fsm->state = ec_fsm_sii_state_write_check; fp@433: } fp@433: fp@433: /*****************************************************************************/ fp@433: fp@433: /** fp@433: SII state: WRITE CHECK. fp@433: */ fp@433: fp@754: void ec_fsm_sii_state_write_check( fp@1507: ec_fsm_sii_t *fsm /**< finite state machine */ fp@1507: ) fp@433: { fp@433: ec_datagram_t *datagram = fsm->datagram; fp@433: fp@637: if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) fp@637: return; fp@505: fp@505: if (datagram->state != EC_DATAGRAM_RECEIVED) { fp@753: fsm->state = ec_fsm_sii_state_error; fp@1921: EC_SLAVE_ERR(fsm->slave, "Failed to receive SII write datagram: "); fp@1822: ec_datagram_print_state(datagram); fp@505: return; fp@505: } fp@505: fp@505: if (datagram->working_counter != 1) { fp@753: fsm->state = ec_fsm_sii_state_error; fp@1921: EC_SLAVE_ERR(fsm->slave, "Reception of SII write datagram failed: "); fp@713: ec_datagram_print_wc_error(datagram); fp@433: return; fp@433: } fp@433: fp@1039: fsm->jiffies_start = datagram->jiffies_sent; fp@433: fsm->check_once_more = 1; fp@433: fp@755: // issue check datagram fp@815: ec_datagram_fprd(datagram, fsm->slave->station_address, 0x502, 2); fp@1225: ec_datagram_zero(datagram); fp@505: fsm->retries = EC_FSM_RETRIES; fp@753: fsm->state = ec_fsm_sii_state_write_check2; fp@433: } fp@433: fp@433: /*****************************************************************************/ fp@433: fp@433: /** fp@433: SII state: WRITE CHECK 2. fp@433: */ fp@433: fp@754: void ec_fsm_sii_state_write_check2( fp@1507: ec_fsm_sii_t *fsm /**< finite state machine */ fp@1507: ) fp@433: { fp@433: ec_datagram_t *datagram = fsm->datagram; fp@1039: unsigned long diff_ms; fp@433: fp@637: if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) fp@637: return; fp@505: fp@505: if (datagram->state != EC_DATAGRAM_RECEIVED) { fp@753: fsm->state = ec_fsm_sii_state_error; fp@1921: EC_SLAVE_ERR(fsm->slave, fp@1921: "Failed to receive SII write check datagram: "); fp@1822: ec_datagram_print_state(datagram); fp@505: return; fp@505: } fp@505: fp@505: if (datagram->working_counter != 1) { fp@753: fsm->state = ec_fsm_sii_state_error; fp@1921: EC_SLAVE_ERR(fsm->slave, fp@1921: "Reception of SII write check datagram failed: "); fp@713: ec_datagram_print_wc_error(datagram); fp@433: return; fp@433: } fp@433: fp@755: #ifdef SII_DEBUG fp@1921: EC_SLAVE_DBG(fsm->slave, 0, "checking SII write state:\n"); fp@1507: ec_print_data(datagram->data, 2); fp@755: #endif fp@755: fp@755: if (EC_READ_U8(datagram->data + 1) & 0x20) { fp@1921: EC_SLAVE_ERR(fsm->slave, "SII: Error on last SII command!\n"); fp@755: fsm->state = ec_fsm_sii_state_error; fp@755: return; fp@755: } fp@755: fp@1507: /* FIXME: some slaves never answer with the busy flag set... fp@1507: * wait a few ms for the write operation to complete. */ fp@1039: diff_ms = (datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ; fp@1039: if (diff_ms < SII_INHIBIT) { fp@755: #ifdef SII_DEBUG fp@1921: EC_SLAVE_DBG(fsm->slave, 0, "too early.\n"); fp@755: #endif fp@755: // issue check datagram again fp@755: fsm->retries = EC_FSM_RETRIES; fp@755: return; fp@1507: } fp@1507: fp@1507: if (EC_READ_U8(datagram->data + 1) & 0x82) { /* busy bit or fp@1507: write operation busy bit */ fp@433: // still busy... timeout? fp@1039: if (diff_ms >= SII_TIMEOUT) { fp@755: if (fsm->check_once_more) { fp@1507: fsm->check_once_more = 0; fp@1507: } else { fp@1921: EC_SLAVE_ERR(fsm->slave, "SII: Write timeout.\n"); fp@753: fsm->state = ec_fsm_sii_state_error; fp@433: return; fp@433: } fp@433: } fp@433: fp@755: // issue check datagram again fp@505: fsm->retries = EC_FSM_RETRIES; fp@433: return; fp@433: } fp@433: fp@433: if (EC_READ_U8(datagram->data + 1) & 0x40) { fp@1921: EC_SLAVE_ERR(fsm->slave, "SII: Write operation failed!\n"); fp@753: fsm->state = ec_fsm_sii_state_error; fp@433: return; fp@433: } fp@433: fp@433: // success fp@753: fsm->state = ec_fsm_sii_state_end; fp@433: } fp@433: fp@433: /*****************************************************************************/ fp@433: fp@433: /** fp@433: State: ERROR. fp@433: */ fp@433: fp@754: void ec_fsm_sii_state_error( fp@1507: ec_fsm_sii_t *fsm /**< finite state machine */ fp@1507: ) fp@433: { fp@433: } fp@433: fp@433: /*****************************************************************************/ fp@433: fp@433: /** fp@433: State: END. fp@433: */ fp@433: fp@754: void ec_fsm_sii_state_end( fp@1507: ec_fsm_sii_t *fsm /**< finite state machine */ fp@1507: ) fp@1507: { fp@1507: } fp@1507: fp@1507: /*****************************************************************************/