fp@433: /****************************************************************************** fp@433: * fp@433: * $Id$ fp@433: * fp@433: * Copyright (C) 2006 Florian Pose, Ingenieurgemeinschaft IgH fp@433: * fp@433: * This file is part of the IgH EtherCAT Master. fp@433: * fp@433: * The IgH EtherCAT Master is free software; you can redistribute it fp@433: * and/or modify it under the terms of the GNU General Public License fp@433: * as published by the Free Software Foundation; either version 2 of the fp@433: * License, or (at your option) any later version. fp@433: * fp@433: * The IgH EtherCAT Master is distributed in the hope that it will be fp@433: * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of fp@433: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the fp@433: * GNU General Public License for more details. fp@433: * fp@433: * You should have received a copy of the GNU General Public License fp@433: * along 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@433: * The right to use EtherCAT Technology is granted and comes free of fp@433: * charge under condition of compatibility of product made by fp@433: * Licensee. People intending to distribute/sell products based on the fp@433: * code, have to sign an agreement to guarantee that products using fp@433: * software based on IgH EtherCAT master stay compatible with the actual fp@433: * EtherCAT specification (which are released themselves as an open fp@433: * standard) as the (only) precondition to have the right to use EtherCAT fp@433: * Technology, IP and trade marks. 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@433: /*****************************************************************************/ fp@433: fp@433: void ec_fsm_sii_start_reading(ec_fsm_sii_t *); fp@433: void ec_fsm_sii_read_check(ec_fsm_sii_t *); fp@433: void ec_fsm_sii_read_fetch(ec_fsm_sii_t *); fp@433: void ec_fsm_sii_start_writing(ec_fsm_sii_t *); fp@433: void ec_fsm_sii_write_check(ec_fsm_sii_t *); fp@433: void ec_fsm_sii_write_check2(ec_fsm_sii_t *); fp@433: void ec_fsm_sii_end(ec_fsm_sii_t *); fp@433: void ec_fsm_sii_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@433: uint16_t offset, /**< offset to read from */ fp@433: ec_fsm_sii_addressing_t mode /**< addressing scheme */ fp@433: ) fp@433: { fp@433: fsm->state = ec_fsm_sii_start_reading; fp@433: fsm->slave = slave; fp@433: fsm->offset = 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@433: uint16_t offset, /**< offset to read from */ fp@433: uint16_t *value, /**< pointer to 2 bytes of data */ fp@433: ec_fsm_sii_addressing_t mode /**< addressing scheme */ fp@433: ) fp@433: { fp@433: fsm->state = ec_fsm_sii_start_writing; fp@433: fsm->slave = slave; fp@433: fsm->offset = 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@433: return fsm->state != ec_fsm_sii_end && fsm->state != ec_fsm_sii_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@433: return fsm->state == ec_fsm_sii_end; fp@433: } fp@433: fp@433: /****************************************************************************** fp@433: * SII state machine 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@433: void ec_fsm_sii_start_reading(ec_fsm_sii_t *fsm /**< finite state machine */) fp@433: { fp@433: ec_datagram_t *datagram = fsm->datagram; fp@433: fp@433: // initiate read operation fp@433: switch (fsm->mode) { fp@433: case EC_FSM_SII_POSITION: fp@433: ec_datagram_apwr(datagram, fsm->slave->ring_position, 0x502, 4); fp@433: break; fp@433: case EC_FSM_SII_NODE: fp@433: ec_datagram_npwr(datagram, fsm->slave->station_address, 0x502, 4); fp@433: break; fp@433: } fp@433: fp@433: EC_WRITE_U8 (datagram->data, 0x00); // read-only access fp@433: EC_WRITE_U8 (datagram->data + 1, 0x01); // request read operation fp@433: EC_WRITE_U16(datagram->data + 2, fsm->offset); fp@433: ec_master_queue_datagram(fsm->slave->master, datagram); fp@433: fsm->state = ec_fsm_sii_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@433: void ec_fsm_sii_read_check(ec_fsm_sii_t *fsm /**< finite state machine */) fp@433: { fp@433: ec_datagram_t *datagram = fsm->datagram; fp@433: fp@433: if (datagram->state != EC_DATAGRAM_RECEIVED fp@433: || datagram->working_counter != 1) { fp@433: EC_ERR("SII: Reception of read datagram failed.\n"); fp@433: fsm->state = ec_fsm_sii_error; fp@433: return; fp@433: } fp@433: fp@433: fsm->cycles_start = datagram->cycles_sent; fp@433: fsm->check_once_more = 1; fp@433: fp@433: // issue check/fetch datagram fp@433: switch (fsm->mode) { fp@433: case EC_FSM_SII_POSITION: fp@433: ec_datagram_aprd(datagram, fsm->slave->ring_position, 0x502, 10); fp@433: break; fp@433: case EC_FSM_SII_NODE: fp@433: ec_datagram_nprd(datagram, fsm->slave->station_address, 0x502, 10); fp@433: break; fp@433: } fp@433: ec_master_queue_datagram(fsm->slave->master, datagram); fp@433: fsm->state = ec_fsm_sii_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@433: fp@433: void ec_fsm_sii_read_fetch(ec_fsm_sii_t *fsm /**< finite state machine */) fp@433: { fp@433: ec_datagram_t *datagram = fsm->datagram; fp@433: fp@433: if (datagram->state != EC_DATAGRAM_RECEIVED fp@433: || datagram->working_counter != 1) { fp@433: EC_ERR("SII: Reception of check/fetch datagram failed.\n"); fp@433: fsm->state = ec_fsm_sii_error; fp@433: return; fp@433: } fp@433: fp@433: // check "busy bit" fp@433: if (EC_READ_U8(datagram->data + 1) & 0x81) { fp@433: // still busy... timeout? fp@433: if (datagram->cycles_received fp@433: - fsm->cycles_start >= (cycles_t) 10 * cpu_khz) { fp@433: if (!fsm->check_once_more) { fp@433: EC_ERR("SII: Read timeout.\n"); fp@433: fsm->state = ec_fsm_sii_error; fp@433: #if 0 fp@433: EC_DBG("SII busy: %02X %02X %02X %02X\n", fp@433: EC_READ_U8(datagram->data + 0), fp@433: EC_READ_U8(datagram->data + 1), fp@433: EC_READ_U8(datagram->data + 2), fp@433: EC_READ_U8(datagram->data + 3)); fp@433: #endif fp@433: return; fp@433: } fp@433: fsm->check_once_more = 0; fp@433: } fp@433: fp@433: // issue check/fetch datagram again fp@433: switch (fsm->mode) { fp@433: case EC_FSM_SII_POSITION: fp@433: ec_datagram_aprd(datagram, fsm->slave->ring_position, 0x502, 10); fp@433: break; fp@433: case EC_FSM_SII_NODE: fp@433: ec_datagram_nprd(datagram, fsm->slave->station_address, 0x502, 10); fp@433: break; fp@433: } fp@433: ec_master_queue_datagram(fsm->slave->master, datagram); fp@433: return; fp@433: } fp@433: fp@433: #if 0 fp@433: EC_DBG("SII rec: %02X %02X %02X %02X - %02X %02X %02X %02X\n", fp@433: EC_READ_U8(datagram->data + 0), EC_READ_U8(datagram->data + 1), fp@433: EC_READ_U8(datagram->data + 2), EC_READ_U8(datagram->data + 3), fp@433: EC_READ_U8(datagram->data + 6), EC_READ_U8(datagram->data + 7), fp@433: EC_READ_U8(datagram->data + 8), EC_READ_U8(datagram->data + 9)); fp@433: #endif fp@433: fp@433: // SII value received. fp@433: memcpy(fsm->value, datagram->data + 6, 4); fp@433: fsm->state = ec_fsm_sii_end; fp@433: } fp@433: fp@433: /*****************************************************************************/ fp@433: fp@433: /** fp@433: SII state: START WRITING. fp@433: Starts reading the slave information interface. fp@433: */ fp@433: fp@433: void ec_fsm_sii_start_writing(ec_fsm_sii_t *fsm /**< finite state machine */) fp@433: { fp@433: ec_datagram_t *datagram = fsm->datagram; fp@433: fp@433: // initiate write operation fp@433: ec_datagram_npwr(datagram, fsm->slave->station_address, 0x502, 8); fp@433: EC_WRITE_U8 (datagram->data, 0x01); // enable write access fp@433: EC_WRITE_U8 (datagram->data + 1, 0x02); // request write operation fp@433: EC_WRITE_U32(datagram->data + 2, fsm->offset); fp@433: memcpy(datagram->data + 6, fsm->value, 2); fp@433: ec_master_queue_datagram(fsm->slave->master, datagram); fp@433: fsm->state = ec_fsm_sii_write_check; fp@433: } fp@433: fp@433: /*****************************************************************************/ fp@433: fp@433: /** fp@433: SII state: WRITE CHECK. fp@433: */ fp@433: fp@433: void ec_fsm_sii_write_check(ec_fsm_sii_t *fsm /**< finite state machine */) fp@433: { fp@433: ec_datagram_t *datagram = fsm->datagram; fp@433: fp@433: if (datagram->state != EC_DATAGRAM_RECEIVED fp@433: || datagram->working_counter != 1) { fp@433: EC_ERR("SII: Reception of write datagram failed.\n"); fp@433: fsm->state = ec_fsm_sii_error; fp@433: return; fp@433: } fp@433: fp@433: fsm->cycles_start = datagram->cycles_sent; fp@433: fsm->check_once_more = 1; fp@433: fp@433: // issue check/fetch datagram fp@433: ec_datagram_nprd(datagram, fsm->slave->station_address, 0x502, 2); fp@433: ec_master_queue_datagram(fsm->slave->master, datagram); fp@433: fsm->state = ec_fsm_sii_write_check2; fp@433: } fp@433: fp@433: /*****************************************************************************/ fp@433: fp@433: /** fp@433: SII state: WRITE CHECK 2. fp@433: */ fp@433: fp@433: void ec_fsm_sii_write_check2(ec_fsm_sii_t *fsm /**< finite state machine */) fp@433: { fp@433: ec_datagram_t *datagram = fsm->datagram; fp@433: fp@433: if (datagram->state != EC_DATAGRAM_RECEIVED fp@433: || datagram->working_counter != 1) { fp@433: EC_ERR("SII: Reception of write check datagram failed.\n"); fp@433: fsm->state = ec_fsm_sii_error; fp@433: return; fp@433: } fp@433: fp@433: if (EC_READ_U8(datagram->data + 1) & 0x82) { fp@433: // still busy... timeout? fp@433: if (datagram->cycles_received fp@433: - fsm->cycles_start >= (cycles_t) 10 * cpu_khz) { fp@433: if (!fsm->check_once_more) { fp@433: EC_ERR("SII: Write timeout.\n"); fp@433: fsm->state = ec_fsm_sii_error; fp@433: return; fp@433: } fp@433: fsm->check_once_more = 0; fp@433: } fp@433: fp@433: // issue check/fetch datagram again fp@433: ec_master_queue_datagram(fsm->slave->master, datagram); fp@433: return; fp@433: } fp@433: fp@433: if (EC_READ_U8(datagram->data + 1) & 0x40) { fp@433: EC_ERR("SII: Write operation failed!\n"); fp@433: fsm->state = ec_fsm_sii_error; fp@433: return; fp@433: } fp@433: fp@433: // success fp@433: fsm->state = ec_fsm_sii_end; fp@433: } fp@433: fp@433: /*****************************************************************************/ fp@433: fp@433: /** fp@433: State: ERROR. fp@433: */ fp@433: fp@433: void ec_fsm_sii_error(ec_fsm_sii_t *fsm /**< finite state machine */) fp@433: { fp@433: } fp@433: fp@433: /*****************************************************************************/ fp@433: fp@433: /** fp@433: State: END. fp@433: */ fp@433: fp@433: void ec_fsm_sii_end(ec_fsm_sii_t *fsm /**< finite state machine */) fp@433: { fp@433: } fp@433: fp@433: /*****************************************************************************/