# HG changeset patch # User Florian Pose # Date 1232360321 0 # Node ID 11ec009e145d9f09f820ac8bca7bf2e46bc9a497 # Parent c55ebaa206f814c424a818143433a96de92290f2 Included FoE patch from Olav Zarges. diff -r c55ebaa206f8 -r 11ec009e145d master/Kbuild.in --- a/master/Kbuild.in Mon Jan 19 10:17:21 2009 +0000 +++ b/master/Kbuild.in Mon Jan 19 10:18:41 2009 +0000 @@ -34,8 +34,10 @@ device.o \ domain.o \ fmmu_config.o \ + foe_request.o \ fsm_change.o \ fsm_coe.o \ + fsm_foe.o \ fsm_master.o \ fsm_pdo.o \ fsm_pdo_entry.o \ diff -r c55ebaa206f8 -r 11ec009e145d master/Makefile.am --- a/master/Makefile.am Mon Jan 19 10:17:21 2009 +0000 +++ b/master/Makefile.am Mon Jan 19 10:18:41 2009 +0000 @@ -35,6 +35,7 @@ doxygen.c \ ethernet.c ethernet.h \ fmmu_config.c fmmu_config.h \ + foe.h \ fsm_change.c fsm_change.h \ fsm_coe.c fsm_coe.h \ fsm_master.c fsm_master.h \ diff -r c55ebaa206f8 -r 11ec009e145d master/cdev.c --- a/master/cdev.c Mon Jan 19 10:17:21 2009 +0000 +++ b/master/cdev.c Mon Jan 19 10:18:41 2009 +0000 @@ -1191,6 +1191,182 @@ return 0; } +/*****************************************************************************/ + +/** Read a file from a slave via FoE. + */ +int ec_cdev_ioctl_slave_foe_read( + ec_master_t *master, /**< EtherCAT master. */ + unsigned long arg /**< ioctl() argument. */ + ) +{ + ec_ioctl_slave_foe_t data; + ec_master_foe_request_t request; + int retval; + + if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { + return -EFAULT; + } + + ec_foe_request_init(&request.req, data.file_name); + ec_foe_request_read(&request.req); + ec_foe_request_alloc(&request.req, 10000); // FIXME + + if (down_interruptible(&master->master_sem)) + return -EINTR; + + if (!(request.slave = ec_master_find_slave( + master, 0, data.slave_position))) { + up(&master->master_sem); + ec_foe_request_clear(&request.req); + EC_ERR("Slave %u does not exist!\n", data.slave_position); + return -EINVAL; + } + + // schedule request. + list_add_tail(&request.list, &master->foe_requests); + + up(&master->master_sem); + + // wait for processing through FSM + if (wait_event_interruptible(master->foe_queue, + request.req.state != EC_REQUEST_QUEUED)) { + // interrupted by signal + down(&master->master_sem); + if (request.req.state == EC_REQUEST_QUEUED) { + list_del(&request.list); + up(&master->master_sem); + ec_foe_request_clear(&request.req); + return -EINTR; + } + // request already processing: interrupt not possible. + up(&master->master_sem); + } + + // wait until master FSM has finished processing + wait_event(master->foe_queue, request.req.state != EC_REQUEST_BUSY); + + data.abort_code = request.req.abort_code; + + if (master->debug_level) { + EC_DBG("%d bytes read via FoE (abort_code = 0x%x).\n", + request.req.data_size, request.req.abort_code); + } + + if (request.req.state != EC_REQUEST_SUCCESS) { + data.data_size = 0; + retval = -EIO; + } else { + if (request.req.data_size > data.buffer_size) { + EC_ERR("Buffer too small.\n"); + ec_foe_request_clear(&request.req); + return -EOVERFLOW; + } + data.data_size = request.req.data_size; + if (copy_to_user((void __user *) data.buffer, + request.req.buffer, data.data_size)) { + ec_foe_request_clear(&request.req); + return -EFAULT; + } + retval = 0; + } + + if (__copy_to_user((void __user *) arg, &data, sizeof(data))) { + retval = -EFAULT; + } + + ec_foe_request_clear(&request.req); + return retval; +} + +/*****************************************************************************/ + +/** Write a file to a slave via FoE + */ +int ec_cdev_ioctl_slave_foe_write( + ec_master_t *master, /**< EtherCAT master. */ + unsigned long arg /**< ioctl() argument. */ + ) +{ + ec_ioctl_slave_foe_t data; + ec_master_foe_request_t request; + int retval; + + if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { + return -EFAULT; + } + + INIT_LIST_HEAD(&request.list); + + ec_foe_request_init(&request.req, data.file_name); + + if (ec_foe_request_alloc(&request.req, data.buffer_size)) { + ec_foe_request_clear(&request.req); + return -ENOMEM; + } + if (copy_from_user(request.req.buffer, + (void __user *) data.buffer, data.buffer_size)) { + ec_foe_request_clear(&request.req); + return -EFAULT; + } + request.req.data_size = data.buffer_size; + ec_foe_request_write(&request.req); + + if (down_interruptible(&master->master_sem)) + return -EINTR; + + if (!(request.slave = ec_master_find_slave( + master, 0, data.slave_position))) { + up(&master->master_sem); + EC_ERR("Slave %u does not exist!\n", data.slave_position); + ec_foe_request_clear(&request.req); + return -EINVAL; + } + + if (master->debug_level) { + EC_DBG("Scheduling FoE write request.\n"); + } + + // schedule FoE write request. + list_add_tail(&request.list, &master->foe_requests); + + up(&master->master_sem); + + // wait for processing through FSM + if (wait_event_interruptible(master->foe_queue, + request.req.state != EC_REQUEST_QUEUED)) { + // interrupted by signal + down(&master->master_sem); + if (request.req.state == EC_REQUEST_QUEUED) { + // abort request + list_del(&request.list); + up(&master->master_sem); + ec_foe_request_clear(&request.req); + return -EINTR; + } + up(&master->master_sem); + } + + // wait until master FSM has finished processing + wait_event(master->foe_queue, request.req.state != EC_REQUEST_BUSY); + + data.abort_code = request.req.abort_code; + + retval = request.req.state == EC_REQUEST_SUCCESS ? 0 : -EIO; + + if (__copy_to_user((void __user *) arg, &data, sizeof(data))) { + retval = -EFAULT; + } + + ec_foe_request_clear(&request.req); + + if (master->debug_level) { + printk ("Finished FoE writing.\n"); + } + + return retval; +} + /****************************************************************************** * File operations *****************************************************************************/ @@ -1276,6 +1452,12 @@ if (!(filp->f_mode & FMODE_WRITE)) return -EPERM; return ec_cdev_ioctl_slave_sii_write(master, arg); + case EC_IOCTL_SLAVE_FOE_READ: + return ec_cdev_ioctl_slave_foe_read(master, arg); + case EC_IOCTL_SLAVE_FOE_WRITE: + if (!(filp->f_mode & FMODE_WRITE)) + return -EPERM; + return ec_cdev_ioctl_slave_foe_write(master, arg); case EC_IOCTL_CONFIG: return ec_cdev_ioctl_config(master, arg); case EC_IOCTL_CONFIG_PDO: diff -r c55ebaa206f8 -r 11ec009e145d master/foe.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/master/foe.h Mon Jan 19 10:18:41 2009 +0000 @@ -0,0 +1,53 @@ +/****************************************************************************** + * + * $Id$ + * + * Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH + * + * This file is part of the IgH EtherCAT Master. + * + * The IgH EtherCAT Master is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * The IgH EtherCAT Master is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with the IgH EtherCAT Master; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Using the EtherCAT technology and brand is permitted in compliance with + * the industrial property and similar rights of Beckhoff Automation GmbH. + * + *****************************************************************************/ + +#ifndef __FOE_H__ +#define __FOE_H__ + +/*****************************************************************************/ + +typedef enum { + FOE_BUSY = 0, + FOE_READY = 1, + FOE_IDLE = 2, + FOE_WC_ERROR = 3, + FOE_RECEIVE_ERROR = 4, + FOE_PROT_ERROR = 5, + FOE_NODATA_ERROR = 6, + FOE_PACKETNO_ERROR = 7, + FOE_OPMODE_ERROR = 8, + FOE_TIMEOUT_ERROR = 9, + FOE_SEND_RX_DATA_ERROR = 10, + FOE_RX_DATA_ACK_ERROR = 11, + FOE_ACK_ERROR = 12, + FOE_MBOX_FETCH_ERROR = 13, + FOE_READ_NODATA_ERROR = 14, + FOE_MBOX_PROT_ERROR = 15, +} ec_foe_error_t; + +/*****************************************************************************/ + +#endif diff -r c55ebaa206f8 -r 11ec009e145d master/foe_request.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/master/foe_request.c Mon Jan 19 10:18:41 2009 +0000 @@ -0,0 +1,201 @@ +/****************************************************************************** + * + * $Id:$ + * + * Copyright (C) 2008 Olav Zarges, imc Meßsysteme GmbH + * + * This file is part of the IgH EtherCAT Master. + * + * The IgH EtherCAT Master is free software; you can redistribute it + * and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * The IgH EtherCAT Master is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the IgH EtherCAT Master; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * The right to use EtherCAT Technology is granted and comes free of + * charge under condition of compatibility of product made by + * Licensee. People intending to distribute/sell products based on the + * code, have to sign an agreement to guarantee that products using + * software based on IgH EtherCAT master stay compatible with the actual + * EtherCAT specification (which are released themselves as an open + * standard) as the (only) precondition to have the right to use EtherCAT + * Technology, IP and trade marks. + * + *****************************************************************************/ + +/** \file + * File-over-EtherCAT request functions. + */ + +/*****************************************************************************/ + +#include +#include + +#include "foe_request.h" + +/*****************************************************************************/ + +/** Default timeout in ms to wait for FoE transfer responses. + */ +#define EC_FOE_REQUEST_RESPONSE_TIMEOUT 3000 + +/*****************************************************************************/ + +void ec_foe_request_clear_data(ec_foe_request_t *); + +/*****************************************************************************/ + +/** FoE request constructor. + */ +void ec_foe_request_init( + ec_foe_request_t *req, /**< FoE request. */ + uint8_t* file_name /** filename */) +{ + req->buffer = NULL; + req->file_name = file_name; + req->buffer_size = 0; + req->data_size = 0; + req->dir = EC_DIR_INVALID; + req->issue_timeout = 0; // no timeout + req->response_timeout = EC_FOE_REQUEST_RESPONSE_TIMEOUT; + req->state = EC_REQUEST_INIT; + req->abort_code = 0x00000000; +} + +/*****************************************************************************/ + +/** FoE request destructor. + */ +void ec_foe_request_clear( + ec_foe_request_t *req /**< FoE request. */ + ) +{ + ec_foe_request_clear_data(req); +} + +/*****************************************************************************/ + +/** FoE request destructor. + */ +void ec_foe_request_clear_data( + ec_foe_request_t *req /**< FoE request. */ + ) +{ + if (req->buffer) { + kfree(req->buffer); + req->buffer = NULL; + } + + req->buffer_size = 0; + req->data_size = 0; +} + +/*****************************************************************************/ + +/** Pre-allocates the data memory. + * + * If the \a buffer_size is already bigger than \a size, nothing is done. + */ +int ec_foe_request_alloc( + ec_foe_request_t *req, /**< FoE request. */ + size_t size /**< Data size to allocate. */ + ) +{ + if (size <= req->buffer_size) + return 0; + + ec_foe_request_clear_data(req); + + if (!(req->buffer = (uint8_t *) kmalloc(size, GFP_KERNEL))) { + EC_ERR("Failed to allocate %u bytes of FoE memory.\n", size); + return -1; + } + + req->buffer_size = size; + req->data_size = 0; + return 0; +} + +/*****************************************************************************/ + +/** Copies FoE data from an external source. + * + * If the \a buffer_size is to small, new memory is allocated. + */ +int ec_foe_request_copy_data( + ec_foe_request_t *req, /**< FoE request. */ + const uint8_t *source, /**< Source data. */ + size_t size /**< Number of bytes in \a source. */ + ) +{ + if (ec_foe_request_alloc(req, size)) + return -1; + + memcpy(req->buffer, source, size); + req->data_size = size; + return 0; +} + +/*****************************************************************************/ + +/** Checks, if the timeout was exceeded. + * + * \return non-zero if the timeout was exceeded, else zero. + */ +int ec_foe_request_timed_out(const ec_foe_request_t *req /**< FoE request. */) +{ + return req->issue_timeout + && jiffies - req->jiffies_start > HZ * req->issue_timeout / 1000; +} + +/*****************************************************************************/ + +void ec_foe_request_timeout(ec_foe_request_t *req, uint32_t timeout) +{ + req->issue_timeout = timeout; +} + +/*****************************************************************************/ + +uint8_t *ec_foe_request_data(ec_foe_request_t *req) +{ + return req->buffer; +} + +/*****************************************************************************/ + +size_t ec_foe_request_data_size(const ec_foe_request_t *req) +{ + return req->data_size; +} + +/*****************************************************************************/ + +void ec_foe_request_read(ec_foe_request_t *req) +{ + req->dir = EC_DIR_INPUT; + req->state = EC_REQUEST_QUEUED; + req->abort_code = 0x00000000; + req->jiffies_start = jiffies; +} + +/*****************************************************************************/ + +void ec_foe_request_write(ec_foe_request_t *req) +{ + req->dir = EC_DIR_OUTPUT; + req->state = EC_REQUEST_QUEUED; + req->abort_code = 0x00000000; + req->jiffies_start = jiffies; +} + +/*****************************************************************************/ diff -r c55ebaa206f8 -r 11ec009e145d master/foe_request.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/master/foe_request.h Mon Jan 19 10:18:41 2009 +0000 @@ -0,0 +1,89 @@ +/****************************************************************************** + * + * $Id:$ + * + * Copyright (C) 2008 Olav Zarges, imc Meßsysteme GmbH + * + * This file is part of the IgH EtherCAT Master. + * + * The IgH EtherCAT Master is free software; you can redistribute it + * and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * The IgH EtherCAT Master is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the IgH EtherCAT Master; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * The right to use EtherCAT Technology is granted and comes free of + * charge under condition of compatibility of product made by + * Licensee. People intending to distribute/sell products based on the + * code, have to sign an agreement to guarantee that products using + * software based on IgH EtherCAT master stay compatible with the actual + * EtherCAT specification (which are released themselves as an open + * standard) as the (only) precondition to have the right to use EtherCAT + * Technology, IP and trade marks. + * + *****************************************************************************/ + +/** + \file + EtherCAT FoE request structure. +*/ + +/*****************************************************************************/ + +#ifndef __EC_FOE_REQUEST_H__ +#define __EC_FOE_REQUEST_H__ + +#include + +#include "../include/ecrt.h" + +#include "globals.h" + +/*****************************************************************************/ + +/** FoE request. + */ +typedef struct { + uint8_t *buffer; /**< Pointer to FoE data. */ + size_t buffer_size; /**< Size of FoE data memory. */ + size_t data_size; /**< Size of FoE data. */ + + uint32_t issue_timeout; /**< Maximum time in ms, the processing of the + request may take. */ + uint32_t response_timeout; /**< Maximum time in ms, the transfer is + retried, if the slave does not respond. */ + ec_direction_t dir; /**< Direction. EC_DIR_OUTPUT means downloading to + the slave, EC_DIR_INPUT means uploading from the + slave. */ + ec_request_state_t state; /**< FoE request state. */ + unsigned long jiffies_start; /**< Jiffies, when the request was issued. */ + unsigned long jiffies_sent; /**< Jiffies, when the upload/download + request was sent. */ + uint8_t *file_name; /**< Pointer to the filename. */ + uint32_t abort_code; /**< FoE request abort code. Zero on success. */ +} ec_foe_request_t; + +/*****************************************************************************/ + +void ec_foe_request_init(ec_foe_request_t *, uint8_t* file_name); +void ec_foe_request_clear(ec_foe_request_t *); + +void ec_foe_request_address(ec_foe_request_t *, uint16_t, uint8_t); +int ec_foe_request_alloc(ec_foe_request_t *, size_t); +int ec_foe_request_copy_data(ec_foe_request_t *, const uint8_t *, size_t); +int ec_foe_request_timed_out(const ec_foe_request_t *); + +void ec_foe_request_write(ec_foe_request_t *); +void ec_foe_request_read(ec_foe_request_t *); + +/*****************************************************************************/ + +#endif diff -r c55ebaa206f8 -r 11ec009e145d master/fsm_foe.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/master/fsm_foe.c Mon Jan 19 10:18:41 2009 +0000 @@ -0,0 +1,851 @@ +/****************************************************************************** + * + * $Id:$ + * + * Copyright (C) 2008 Olav Zarges, imc Meßsysteme GmbH + * + * This file is part of the IgH EtherCAT Master. + * + * The IgH EtherCAT Master is free software; you can redistribute it + * and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * The IgH EtherCAT Master is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the IgH EtherCAT Master; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * The right to use EtherCAT Technology is granted and comes free of + * charge under condition of compatibility of product made by + * Licensee. People intending to distribute/sell products based on the + * code, have to sign an agreement to guarantee that products using + * software based on IgH EtherCAT master stay compatible with the actual + * EtherCAT specification (which are released themselves as an open + * standard) as the (only) precondition to have the right to use EtherCAT + * Technology, IP and trade marks. + * + *****************************************************************************/ + +/** + \file + EtherCAT FoE state machines. +*/ + +/*****************************************************************************/ + +#include "globals.h" +#include "master.h" +#include "mailbox.h" +#include "fsm_foe.h" +#include "foe.h" + +/*****************************************************************************/ + +/** Maximum time in ms to wait for responses when reading out the dictionary. + */ +#define EC_FSM_FOE_TIMEOUT 3000 + +#define EC_MBOX_TYPE_FILEACCESS 0x04 + +/*****************************************************************************/ + +int ec_foe_prepare_data_send( ec_fsm_foe_t * ); +int ec_foe_prepare_wrq_send( ec_fsm_foe_t * ); +int ec_foe_prepare_rrq_send( ec_fsm_foe_t * ); +int ec_foe_prepare_send_ack( ec_fsm_foe_t * ); + +void ec_foe_set_tx_error( ec_fsm_foe_t *, uint32_t ); +void ec_foe_set_rx_error( ec_fsm_foe_t *, uint32_t ); + +void ec_fsm_foe_write(ec_fsm_foe_t * ); +void ec_fsm_foe_read(ec_fsm_foe_t * ); +void ec_fsm_foe_end( ec_fsm_foe_t * ); +void ec_fsm_foe_error( ec_fsm_foe_t * ); + +void ec_fsm_foe_state_wrq_sent( ec_fsm_foe_t * ); +void ec_fsm_foe_state_rrq_sent( ec_fsm_foe_t * ); + +void ec_fsm_foe_state_ack_check( ec_fsm_foe_t * ); +void ec_fsm_foe_state_ack_read( ec_fsm_foe_t * ); + +void ec_fsm_foe_state_data_sent( ec_fsm_foe_t * ); + +void ec_fsm_foe_state_data_check( ec_fsm_foe_t * ); +void ec_fsm_foe_state_data_read ( ec_fsm_foe_t * ); +void ec_fsm_foe_state_sent_ack( ec_fsm_foe_t * ); + +void ec_fsm_foe_write_start( ec_fsm_foe_t * ); +void ec_fsm_foe_read_start(ec_fsm_foe_t * ); + +/*****************************************************************************/ + +/** + Constructor. +*/ + +void ec_fsm_foe_init(ec_fsm_foe_t *fsm, /**< finite state machine */ + ec_datagram_t *datagram /**< datagram */ + ) +{ + fsm->state = NULL; + fsm->datagram = datagram; + fsm->rx_errors = 0; + fsm->tx_errors = 0; +} + +/*****************************************************************************/ + +/** + Destructor. +*/ + +void ec_fsm_foe_clear(ec_fsm_foe_t *fsm /**< finite state machine */) +{ +} + +/*****************************************************************************/ + +/** + Executes the current state of the state machine. + \return false, if state machine has terminated +*/ + +int ec_fsm_foe_exec(ec_fsm_foe_t *fsm /**< finite state machine */) +{ + fsm->state(fsm); + + return fsm->state != ec_fsm_foe_end && fsm->state != ec_fsm_foe_error; +} + +/*****************************************************************************/ + +/** + Returns, if the state machine terminated with success. + \return non-zero if successful. +*/ + +int ec_fsm_foe_success(ec_fsm_foe_t *fsm /**< Finite state machine */) +{ + return fsm->state == ec_fsm_foe_end; +} + +/*****************************************************************************/ + +void ec_fsm_foe_transfer( + ec_fsm_foe_t *fsm, /**< State machine. */ + ec_slave_t *slave, /**< EtherCAT slave. */ + ec_foe_request_t *request /**< Sdo request. */ + ) +{ + fsm->slave = slave; + fsm->request = request; + if (request->dir == EC_DIR_OUTPUT) { + fsm->state = ec_fsm_foe_write; + } + else { + fsm->state = ec_fsm_foe_read; + } +} + +/*****************************************************************************/ + +/** + State: ERROR. +*/ + +void ec_fsm_foe_error(ec_fsm_foe_t *fsm /**< finite state machine */) +{ +#ifdef myDEBUG + printk("ec_fsm_foe_error()\n"); +#endif +} + +/*****************************************************************************/ + +/** + State: END. +*/ + +void ec_fsm_foe_end(ec_fsm_foe_t *fsm /**< finite state machine */) +{ +#ifdef myDEBUG + printk("ec_fsm_foe_end\n"); +#endif +} + +/*****************************************************************************/ + +#define EC_MBOX_HEADER_SIZE 6 +// uint16_t Length +// uint16_t Address +// uint8_t reserved +// uint8_t Type:4 +// uint8_t Counter:4 + +#define EC_FOE_HEADER_SIZE 6 +// uint8_t OpMode +// uint8_t reserved +// uint32_t PacketNo, Password, ErrorCode + +enum { + EC_FOE_OPMODE_RRQ = 1, + EC_FOE_OPMODE_WRQ = 2, + EC_FOE_OPMODE_DATA = 3, + EC_FOE_OPMODE_ACK = 4, + EC_FOE_OPMODE_ERR = 5, + EC_FOE_OPMODE_BUSY = 6 +} ec_foe_opmode_t; + +/*****************************************************************************/ +/** + Sends a file or the next fragment. +*/ + +int ec_foe_prepare_data_send( ec_fsm_foe_t *fsm ) { + size_t remaining_size, current_size; + uint8_t* data; + + remaining_size = fsm->tx_buffer_size - fsm->tx_buffer_offset; + + if (remaining_size < fsm->slave->sii.tx_mailbox_size - EC_MBOX_HEADER_SIZE - EC_FOE_HEADER_SIZE) { + current_size = remaining_size; + fsm->tx_last_packet = 1; + } + else { + current_size = fsm->slave->sii.tx_mailbox_size - EC_MBOX_HEADER_SIZE - EC_FOE_HEADER_SIZE; + } + + if (!(data = ec_slave_mbox_prepare_send(fsm->slave, fsm->datagram, + EC_MBOX_TYPE_FILEACCESS, current_size + EC_FOE_HEADER_SIZE))) + return -1; + + EC_WRITE_U8 ( data, EC_FOE_OPMODE_DATA ); // OpMode = DataBlock req. + EC_WRITE_U32( data + 2, fsm->tx_packet_no ); // PacketNo, Password + + memcpy(data + EC_FOE_HEADER_SIZE, fsm->tx_buffer + fsm->tx_buffer_offset, current_size); + + fsm->tx_current_size = current_size; + + return 0; +} + +/*****************************************************************************/ +/** + Prepare a write request (WRQ) with filename +*/ + +int ec_foe_prepare_wrq_send( ec_fsm_foe_t *fsm ) { + size_t current_size; + uint8_t *data; + + fsm->tx_buffer_offset = 0; + fsm->tx_current_size = 0; + fsm->tx_packet_no = 0; + fsm->tx_last_packet = 0; + + current_size = fsm->tx_filename_len; + + if (!(data = ec_slave_mbox_prepare_send(fsm->slave, fsm->datagram, + EC_MBOX_TYPE_FILEACCESS, current_size + EC_FOE_HEADER_SIZE))) + return -1; + + EC_WRITE_U16( data, EC_FOE_OPMODE_WRQ); // fsm write request + EC_WRITE_U32( data + 2, fsm->tx_packet_no ); + + memcpy(data + EC_FOE_HEADER_SIZE, fsm->tx_filename, current_size); + + return 0; +} + +/*****************************************************************************/ + +char tx_buffer[0x1000]; +void ec_fsm_foe_write(ec_fsm_foe_t *fsm /**< finite state machine */) +{ + fsm->tx_buffer = fsm->request->buffer; + fsm->tx_buffer_size = fsm->request->data_size; + fsm->tx_buffer_offset = 0; + + fsm->tx_filename = fsm->request->file_name; + fsm->tx_filename_len = strlen(fsm->tx_filename); + + fsm->state = ec_fsm_foe_write_start; + +#ifdef use_ext_buffer + { + int i; + fsm->tx_data = tx_buffer; + for (i=0 ; itx_data_len = sizeof(tx_buffer); + } +#endif +} + +/*****************************************************************************/ +/** + Initializes the SII write state machine. +*/ + +void ec_fsm_foe_write_start(ec_fsm_foe_t *fsm /**< finite state machine */) +{ + ec_slave_t *slave = fsm->slave; + + fsm->tx_buffer_offset = 0; + fsm->tx_current_size = 0; + fsm->tx_packet_no = 0; + fsm->tx_last_packet = 0; + +#ifdef myDEBUG + printk("ec_fsm_foe_write_start()\n"); +#endif + + if (!(slave->sii.mailbox_protocols & EC_MBOX_FOE)) { + ec_foe_set_tx_error(fsm, FOE_MBOX_PROT_ERROR); + EC_ERR("Slave %u does not support FoE!\n", slave->ring_position); + return; + } + + if (ec_foe_prepare_wrq_send(fsm)) { + ec_foe_set_tx_error(fsm, FOE_PROT_ERROR); + return; + } + + fsm->state = ec_fsm_foe_state_wrq_sent; +} + +/*****************************************************************************/ + +void ec_fsm_foe_state_ack_check( ec_fsm_foe_t *fsm ) { + ec_datagram_t *datagram = fsm->datagram; + ec_slave_t *slave = fsm->slave; + +#ifdef myDEBUG +// printk("ec_fsm_foe_ack_check()\n"); +#endif + if (datagram->state != EC_DATAGRAM_RECEIVED) { + ec_foe_set_rx_error(fsm, FOE_RECEIVE_ERROR); + EC_ERR("Failed to receive FoE mailbox check datagram for slave %u" + " (datagram state %u).\n", + slave->ring_position, datagram->state); + return; + } + + if (datagram->working_counter != 1) { + // slave hat noch nichts in die Mailbox getan + ec_foe_set_rx_error(fsm, FOE_WC_ERROR); + EC_ERR("Reception of FoE mailbox check datagram failed on slave %u: ", + slave->ring_position); + ec_datagram_print_wc_error(datagram); + return; + } + + if (!ec_slave_mbox_check(datagram)) { + unsigned long diff_ms = + (datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ; + if (diff_ms >= EC_FSM_FOE_TIMEOUT) { + ec_foe_set_tx_error(fsm, FOE_TIMEOUT_ERROR); + EC_ERR("Timeout while waiting for ack response " + "on slave %u.\n", slave->ring_position); + return; + } +// EC_ERR("WAIT!!!!!!!!!!!!!\n"); + ec_slave_mbox_prepare_check(slave, datagram); // can not fail. + fsm->retries = EC_FSM_RETRIES; + return; + } + + // Fetch response + ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail. + + fsm->retries = EC_FSM_RETRIES; + fsm->state = ec_fsm_foe_state_ack_read; +} + +/*****************************************************************************/ + +void ec_fsm_foe_state_ack_read( ec_fsm_foe_t *fsm ) { + + ec_datagram_t *datagram = fsm->datagram; + ec_slave_t *slave = fsm->slave; + uint8_t *data, mbox_prot; + uint16_t opMode; + size_t rec_size; + +#ifdef myDEBUG + printk("ec_fsm_foe_ack_read()\n"); +#endif + if (datagram->state != EC_DATAGRAM_RECEIVED) { + ec_foe_set_rx_error(fsm, FOE_RECEIVE_ERROR); + EC_ERR("Failed to receive FoE ack response datagram for" + " slave %u (datagram state %u).\n", + slave->ring_position, datagram->state); + return; + } + + if (datagram->working_counter != 1) { + ec_foe_set_rx_error(fsm, FOE_WC_ERROR); + EC_ERR("Reception of FoE ack response failed on slave %u: ", + slave->ring_position); + ec_datagram_print_wc_error(datagram); + return; + } + + if (!(data = ec_slave_mbox_fetch(fsm->slave, datagram, &mbox_prot, &rec_size))) { + ec_foe_set_tx_error(fsm, FOE_PROT_ERROR); + return; + } + + if (mbox_prot != EC_MBOX_TYPE_FILEACCESS) { // FoE + ec_foe_set_tx_error(fsm, FOE_MBOX_PROT_ERROR); + EC_ERR("Received mailbox protocol 0x%02X as response.\n", mbox_prot); + return; + } + + opMode = EC_READ_U16(data); + + if ( opMode == EC_FOE_OPMODE_BUSY ) { + // slave ist noch nicht bereit + if (ec_foe_prepare_data_send(fsm)) { + ec_foe_set_tx_error(fsm, FOE_PROT_ERROR); + EC_ERR("Slave is busy.\n"); + return; + } + fsm->state = ec_fsm_foe_state_data_sent; + return; + } + + if ( opMode == EC_FOE_OPMODE_ACK ) { + fsm->tx_packet_no++; + fsm->tx_buffer_offset += fsm->tx_current_size; + + if (fsm->tx_last_packet) { + fsm->state = ec_fsm_foe_end; + return; + } + + if (ec_foe_prepare_data_send(fsm)) { + ec_foe_set_tx_error(fsm, FOE_PROT_ERROR); + return; + } + fsm->state = ec_fsm_foe_state_data_sent; + return; + } + ec_foe_set_tx_error(fsm, FOE_ACK_ERROR); +} + +/*****************************************************************************/ +/** + State: WRQ SENT. + Checks is the previous transmit datagram succeded and sends the next + fragment, if necessary. +*/ + +void ec_fsm_foe_state_wrq_sent( ec_fsm_foe_t *fsm ) { + ec_datagram_t *datagram = fsm->datagram; + ec_slave_t *slave = fsm->slave; + +#ifdef myDEBUG + printk("ec_foe_state_sent_wrq()\n"); +#endif + if (datagram->state != EC_DATAGRAM_RECEIVED) { + ec_foe_set_rx_error(fsm, FOE_RECEIVE_ERROR); + EC_ERR("Failed to send FoE WRQ for slave %u" + " (datagram state %u).\n", + slave->ring_position, datagram->state); + return; + } + + if (datagram->working_counter != 1) { + // slave hat noch nichts in die Mailbox getan + ec_foe_set_rx_error(fsm, FOE_WC_ERROR); + EC_ERR("Reception of FoE WRQ failed on slave %u: ", + slave->ring_position); + ec_datagram_print_wc_error(datagram); + return; + } + + fsm->jiffies_start = datagram->jiffies_sent; + + ec_slave_mbox_prepare_check(fsm->slave, datagram); // can not fail. + + fsm->retries = EC_FSM_RETRIES; + fsm->state = ec_fsm_foe_state_ack_check; +} + +/*****************************************************************************/ +/** + State: WRQ SENT. + Checks is the previous transmit datagram succeded and sends the next + fragment, if necessary. +*/ + +void ec_fsm_foe_state_data_sent( ec_fsm_foe_t *fsm ) { + ec_datagram_t *datagram = fsm->datagram; + ec_slave_t *slave = fsm->slave; + +#ifdef myDEBUG + printk("ec_fsm_foe_state_data_sent()\n"); +#endif + if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) { + ec_foe_set_tx_error(fsm, FOE_RECEIVE_ERROR); + EC_ERR("Failed to receive FoE ack response datagram for" + " slave %u (datagram state %u).\n", + slave->ring_position, datagram->state); + return; + } + + if (fsm->datagram->working_counter != 1) { + ec_foe_set_tx_error(fsm, FOE_WC_ERROR); + EC_ERR("Reception of FoE data send failed on slave %u: ", + slave->ring_position); + ec_datagram_print_wc_error(datagram); + return; + } + + ec_slave_mbox_prepare_check(fsm->slave, fsm->datagram); + fsm->jiffies_start = jiffies; + fsm->retries = EC_FSM_RETRIES; + fsm->state = ec_fsm_foe_state_ack_check; +} + +/*****************************************************************************/ +/** + Prepare a read request (RRQ) with filename +*/ + +int ec_foe_prepare_rrq_send( ec_fsm_foe_t *fsm ) { + size_t current_size; + uint8_t *data; + + current_size = fsm->rx_filename_len; + + if (!(data = ec_slave_mbox_prepare_send(fsm->slave, fsm->datagram, + EC_MBOX_TYPE_FILEACCESS, current_size + EC_FOE_HEADER_SIZE))) + return -1; + + EC_WRITE_U16( data, EC_FOE_OPMODE_RRQ); // fsm read request + EC_WRITE_U32( data + 2, 0 ); + + memcpy(data + EC_FOE_HEADER_SIZE, fsm->rx_filename, current_size); + + return 0; +} + + +/*****************************************************************************/ + +int ec_foe_prepare_send_ack( ec_fsm_foe_t *foe ) { + uint8_t *data; + + if (!(data = ec_slave_mbox_prepare_send(foe->slave, foe->datagram, + EC_MBOX_TYPE_FILEACCESS, EC_FOE_HEADER_SIZE))) + return -1; + + EC_WRITE_U16( data, EC_FOE_OPMODE_ACK); + EC_WRITE_U32( data + 2, foe->rx_expected_packet_no ); + + return 0; +} + +/*****************************************************************************/ +/** + State: RRQ SENT. + Checks is the previous transmit datagram succeded and sends the next + fragment, if necessary. +*/ + +void ec_fsm_foe_state_rrq_sent( ec_fsm_foe_t *fsm ) { + ec_datagram_t *datagram = fsm->datagram; + ec_slave_t *slave = fsm->slave; + +#ifdef myDEBUG + printk("ec_foe_state_rrq_sent()\n"); +#endif + if (datagram->state != EC_DATAGRAM_RECEIVED) { + ec_foe_set_rx_error(fsm, FOE_RECEIVE_ERROR); + EC_ERR("Failed to send FoE RRQ for slave %u" + " (datagram state %u).\n", + slave->ring_position, datagram->state); + return; + } + + if (datagram->working_counter != 1) { + // slave hat noch nichts in die Mailbox getan + ec_foe_set_rx_error(fsm, FOE_WC_ERROR); + EC_ERR("Reception of FoE RRQ failed on slave %u: ", + slave->ring_position); + ec_datagram_print_wc_error(datagram); + return; + } + + fsm->jiffies_start = datagram->jiffies_sent; + + ec_slave_mbox_prepare_check(fsm->slave, datagram); // can not fail. + + fsm->retries = EC_FSM_RETRIES; + fsm->state = ec_fsm_foe_state_data_check; +} + +/*****************************************************************************/ + +#ifdef myDEBUG +char rx_buffer[0x8000]; +#endif + +void ec_fsm_foe_read(ec_fsm_foe_t *fsm /**< finite state machine */) +{ + fsm->state = ec_fsm_foe_read_start; + fsm->rx_filename = fsm->request->file_name; + fsm->rx_filename_len = strlen(fsm->rx_filename); + + fsm->rx_buffer = fsm->request->buffer; + fsm->rx_buffer_size = fsm->request->buffer_size; + +#ifdef use_ext_buffer + fsm->rx_buffer = rx_buffer; + fsm->rx_buffer_size = sizeof(rx_buffer); +#endif +} + +/*****************************************************************************/ + +void ec_fsm_foe_read_start(ec_fsm_foe_t *fsm /**< finite state machine */) +{ + size_t current_size; + ec_slave_t *slave = fsm->slave; + + fsm->rx_buffer_offset = 0; + fsm->rx_current_size = 0; + fsm->rx_packet_no = 0; + fsm->rx_expected_packet_no = 1; + fsm->rx_last_packet = 0; + + current_size = fsm->rx_filename_len; + +#ifdef myDEBUG + printk("ec_fsm_foe_read_start()\n"); +#endif + if (!(slave->sii.mailbox_protocols & EC_MBOX_FOE)) { + ec_foe_set_tx_error(fsm, FOE_MBOX_PROT_ERROR); + EC_ERR("Slave %u does not support FoE!\n", slave->ring_position); + return; + } + + if (ec_foe_prepare_rrq_send(fsm)) { + ec_foe_set_rx_error(fsm, FOE_PROT_ERROR); + return; + } + + fsm->state = ec_fsm_foe_state_rrq_sent; +} + +/*****************************************************************************/ + +void ec_fsm_foe_state_data_check ( ec_fsm_foe_t *fsm ) { + ec_datagram_t *datagram = fsm->datagram; + ec_slave_t *slave = fsm->slave; + +#ifdef myDEBUG + printk("ec_fsm_foe_state_data_check()\n"); +#endif + if (datagram->state != EC_DATAGRAM_RECEIVED) { + ec_foe_set_rx_error(fsm, FOE_RECEIVE_ERROR); + EC_ERR("Failed to send FoE DATA READ for slave %u" + " (datagram state %u).\n", + slave->ring_position, datagram->state); + return; + } + + if (datagram->working_counter != 1) { + ec_foe_set_rx_error(fsm, FOE_WC_ERROR); + EC_ERR("Reception of FoE DATA READ on slave %u: ", + slave->ring_position); + ec_datagram_print_wc_error(datagram); + return; + } + + if (!ec_slave_mbox_check(datagram)) { + unsigned long diff_ms = + (datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ; + if (diff_ms >= EC_FSM_FOE_TIMEOUT) { + ec_foe_set_tx_error(fsm, FOE_TIMEOUT_ERROR); + EC_ERR("Timeout while waiting for ack response " + "on slave %u.\n", slave->ring_position); + return; + } + + ec_slave_mbox_prepare_check(slave, datagram); // can not fail. + fsm->retries = EC_FSM_RETRIES; + return; + } + + // Fetch response + ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail. + + fsm->retries = EC_FSM_RETRIES; + fsm->state = ec_fsm_foe_state_data_read; + +} + +/*****************************************************************************/ + +void ec_fsm_foe_state_data_read ( ec_fsm_foe_t *fsm ) { + size_t rec_size; + uint8_t *data, opMode, packet_no, mbox_prot; + + ec_datagram_t *datagram = fsm->datagram; + ec_slave_t *slave = fsm->slave; + +#ifdef myDEBUG + printk("ec_fsm_foe_state_data_read()\n"); +#endif + if (datagram->state != EC_DATAGRAM_RECEIVED) { + ec_foe_set_rx_error(fsm, FOE_RECEIVE_ERROR); + EC_ERR("Failed to receive FoE DATA READ datagram for" + " slave %u (datagram state %u).\n", + slave->ring_position, datagram->state); + return; + } + + if (datagram->working_counter != 1) { + ec_foe_set_rx_error(fsm, FOE_WC_ERROR); + EC_ERR("Reception of FoE DATA READ failed on slave %u: ", + slave->ring_position); + ec_datagram_print_wc_error(datagram); + return; + } + + if (!(data = ec_slave_mbox_fetch(slave, datagram, &mbox_prot, &rec_size))) { + ec_foe_set_rx_error(fsm, FOE_MBOX_FETCH_ERROR); + return; + } + + if (mbox_prot != EC_MBOX_TYPE_FILEACCESS) { // FoE + EC_ERR("Received mailbox protocol 0x%02X as response.\n", mbox_prot); + ec_foe_set_rx_error(fsm, FOE_PROT_ERROR); + return; + } + + opMode = EC_READ_U16(data); + + if (opMode == EC_FOE_OPMODE_BUSY) { + if (ec_foe_prepare_send_ack(fsm)) { + ec_foe_set_rx_error(fsm, FOE_PROT_ERROR); + } + return; + } + + if (opMode != EC_FOE_OPMODE_DATA) { + ec_foe_set_rx_error(fsm, FOE_OPMODE_ERROR); + return; + } + + packet_no = EC_READ_U16(data + 2); + if (packet_no != fsm->rx_expected_packet_no) { + ec_foe_set_rx_error(fsm, FOE_PACKETNO_ERROR); + return; + } + + rec_size -= EC_FOE_HEADER_SIZE; + + if ( fsm->rx_buffer_size >= fsm->rx_buffer_offset + rec_size ) { + memcpy ( fsm->rx_buffer + fsm->rx_buffer_offset, data + EC_FOE_HEADER_SIZE, rec_size ); + fsm->rx_buffer_offset += rec_size; + } + + fsm->rx_last_packet = (rec_size + EC_MBOX_HEADER_SIZE + EC_FOE_HEADER_SIZE != fsm->slave->sii.rx_mailbox_size); + + if (fsm->rx_last_packet || + slave->sii.rx_mailbox_size - EC_MBOX_HEADER_SIZE - EC_FOE_HEADER_SIZE + fsm->rx_buffer_offset <= fsm->rx_buffer_size) { + // either it was the last packet or a new packet will fit into the delivered buffer +#ifdef myDEBUG + printk ("last_packet=true\n"); +#endif + if (ec_foe_prepare_send_ack(fsm)) { + ec_foe_set_rx_error(fsm, FOE_RX_DATA_ACK_ERROR); + return; + } + + fsm->state = ec_fsm_foe_state_sent_ack; + } + else { + // no more data fits into the deliverd buffer + // ... wait for new read request (an den Treiber) + printk ("ERROR: data doesn't fit in receive buffer\n"); + printk (" rx_buffer_size = %d\n", fsm->rx_buffer_size); + printk (" rx_buffer_offset= %d\n", fsm->rx_buffer_offset); + printk (" rec_size = %d\n", rec_size); + printk (" rx_mailbox_size = %d\n", slave->sii.rx_mailbox_size); + printk (" rx_last_packet = %d\n", fsm->rx_last_packet); +// fsm->state = ec_fsm_state_wait_next_read; + fsm->request->abort_code = FOE_READY; + } +} + +/*****************************************************************************/ + +void ec_fsm_foe_state_sent_ack( ec_fsm_foe_t *fsm ) { + + ec_datagram_t *datagram = fsm->datagram; + ec_slave_t *slave = fsm->slave; + +#ifdef myDEBUG + printk("ec_foe_state_sent_ack()\n"); +#endif + if (datagram->state != EC_DATAGRAM_RECEIVED) { + ec_foe_set_rx_error(fsm, FOE_RECEIVE_ERROR); + EC_ERR("Failed to send FoE ACK for slave %u" + " (datagram state %u).\n", + slave->ring_position, datagram->state); + return; + } + + if (datagram->working_counter != 1) { + // slave hat noch nichts in die Mailbox getan + ec_foe_set_rx_error(fsm, FOE_WC_ERROR); + EC_ERR("Reception of FoE ACK failed on slave %u: ", + slave->ring_position); + ec_datagram_print_wc_error(datagram); + return; + } + + fsm->jiffies_start = datagram->jiffies_sent; + + ec_slave_mbox_prepare_check(fsm->slave, datagram); // can not fail. + + if (fsm->rx_last_packet) { + fsm->rx_expected_packet_no = 0; + fsm->request->data_size = fsm->rx_buffer_offset; + fsm->state = ec_fsm_foe_end; + } + else { + fsm->rx_expected_packet_no++; + fsm->retries = EC_FSM_RETRIES; + fsm->state = ec_fsm_foe_state_data_check; + } +} + +/*****************************************************************************/ + +void ec_foe_set_tx_error( ec_fsm_foe_t *fsm, uint32_t errorcode ) { + fsm->tx_errors++; + fsm->request->abort_code = errorcode; + fsm->state = ec_fsm_foe_error; +} + +/*****************************************************************************/ + +void ec_foe_set_rx_error( ec_fsm_foe_t *fsm, uint32_t errorcode ) { + fsm->rx_errors++; + fsm->request->abort_code = errorcode; + fsm->state = ec_fsm_foe_error; +} + +/*****************************************************************************/ diff -r c55ebaa206f8 -r 11ec009e145d master/fsm_foe.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/master/fsm_foe.h Mon Jan 19 10:18:41 2009 +0000 @@ -0,0 +1,102 @@ +/****************************************************************************** + * + * $Id:$ + * + * Copyright (C) 2008 Olav Zarges, imc Meßsysteme GmbH + * + * This file is part of the IgH EtherCAT Master. + * + * The IgH EtherCAT Master is free software; you can redistribute it + * and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * The IgH EtherCAT Master is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the IgH EtherCAT Master; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * The right to use EtherCAT Technology is granted and comes free of + * charge under condition of compatibility of product made by + * Licensee. People intending to distribute/sell products based on the + * code, have to sign an agreement to guarantee that products using + * software based on IgH EtherCAT master stay compatible with the actual + * EtherCAT specification (which are released themselves as an open + * standard) as the (only) precondition to have the right to use EtherCAT + * Technology, IP and trade marks. + * + *****************************************************************************/ + +/** + \file + EtherCAT FoE state machines. +*/ + +/*****************************************************************************/ + +#ifndef __EC_FSM_FOE_H__ +#define __EC_FSM_FOE_H__ + +#include "globals.h" +#include "../include/ecrt.h" +#include "datagram.h" +#include "slave.h" +#include "foe_request.h" + +/*****************************************************************************/ + +typedef struct ec_fsm_foe ec_fsm_foe_t; /**< \see ec_fsm_foe */ + +/** Finite state machines for the CANopen-over-EtherCAT protocol. + */ +struct ec_fsm_foe { + ec_slave_t *slave; /**< slave the FSM runs on */ + ec_datagram_t *datagram; /**< datagram used in the state machine */ + unsigned int retries; /**< retries upon datagram timeout */ + + void (*state)(ec_fsm_foe_t *); /**< FoE state function */ + unsigned long jiffies_start; /**< FoE timestamp. */ + uint8_t subindex; /**< current subindex */ + ec_foe_request_t *request; /**< FoE request */ + uint8_t toggle; /**< toggle bit for segment commands */ + + uint32_t tx_errors; + uint8_t *tx_buffer; + uint32_t tx_buffer_size; + uint32_t tx_buffer_offset; + uint32_t tx_last_packet; + uint32_t tx_packet_no; + uint32_t tx_current_size; + uint8_t *tx_filename; + uint32_t tx_filename_len; + + + uint32_t rx_errors; + uint8_t *rx_buffer; + uint32_t rx_buffer_size; + uint32_t rx_buffer_offset; + uint32_t rx_current_size; + uint32_t rx_packet_no; + uint32_t rx_expected_packet_no; + uint32_t rx_last_packet; + uint8_t *rx_filename; + uint32_t rx_filename_len; +}; + +/*****************************************************************************/ + +void ec_fsm_foe_init(ec_fsm_foe_t *, ec_datagram_t *); +void ec_fsm_foe_clear(ec_fsm_foe_t *); + +int ec_fsm_foe_exec(ec_fsm_foe_t *); +int ec_fsm_foe_success(ec_fsm_foe_t *); + +void ec_fsm_foe_transfer(ec_fsm_foe_t *, ec_slave_t *, ec_foe_request_t *); + +/*****************************************************************************/ + +#endif diff -r c55ebaa206f8 -r 11ec009e145d master/fsm_master.c --- a/master/fsm_master.c Mon Jan 19 10:17:21 2009 +0000 +++ b/master/fsm_master.c Mon Jan 19 10:18:41 2009 +0000 @@ -39,6 +39,7 @@ #endif #include "fsm_master.h" +#include "fsm_foe.h" /*****************************************************************************/ @@ -52,6 +53,7 @@ void ec_fsm_master_state_write_sii(ec_fsm_master_t *); void ec_fsm_master_state_sdo_dictionary(ec_fsm_master_t *); void ec_fsm_master_state_sdo_request(ec_fsm_master_t *); +void ec_fsm_master_state_foe_request(ec_fsm_master_t *); /*****************************************************************************/ @@ -73,6 +75,7 @@ // init sub-state-machines ec_fsm_coe_init(&fsm->fsm_coe, fsm->datagram); + ec_fsm_foe_init(&fsm->fsm_foe, fsm->datagram); ec_fsm_pdo_init(&fsm->fsm_pdo, &fsm->fsm_coe); ec_fsm_change_init(&fsm->fsm_change, fsm->datagram); ec_fsm_slave_config_init(&fsm->fsm_slave_config, fsm->datagram, @@ -92,6 +95,7 @@ { // clear sub-state machines ec_fsm_coe_clear(&fsm->fsm_coe); + ec_fsm_foe_clear(&fsm->fsm_foe); ec_fsm_pdo_clear(&fsm->fsm_pdo); ec_fsm_change_clear(&fsm->fsm_change); ec_fsm_slave_config_clear(&fsm->fsm_slave_config); @@ -209,7 +213,7 @@ } else { master->scan_busy = 1; up(&master->scan_sem); - + // topology change when scan is allowed: // clear all slaves and scan the bus fsm->topology_change_pending = 0; @@ -278,7 +282,7 @@ /*****************************************************************************/ /** Check for pending SII write requests and process one. - * + * * \return non-zero, if an SII write request is processed. */ int ec_fsm_master_action_process_sii( @@ -318,7 +322,7 @@ /*****************************************************************************/ /** Check for pending SDO requests and process one. - * + * * \return non-zero, if an SDO request is processed. */ int ec_fsm_master_action_process_sdo( @@ -367,7 +371,7 @@ } } } - + // search the first external request to be processed while (1) { if (list_empty(&master->slave_sdo_requests)) @@ -408,6 +412,50 @@ /*****************************************************************************/ +/** Check for pending FoE requests and process one. + * + * \return non-zero, if an FoE request is processed. + */ +int ec_fsm_master_action_process_foe( + ec_fsm_master_t *fsm /**< Master state machine. */ + ) +{ + ec_master_t *master = fsm->master; + ec_slave_t *slave; + ec_master_foe_request_t *request; + + // search the first request to be processed + while (1) { + if (list_empty(&master->foe_requests)) + break; + + // get first request + request = list_entry(master->foe_requests.next, + ec_master_foe_request_t, list); + list_del_init(&request->list); // dequeue + request->req.state = EC_REQUEST_BUSY; + slave = request->slave; + + EC_DBG("---- Master read command from queue ----\n"); + // found pending FOE write operation. execute it! + if (master->debug_level) + EC_DBG("Writing FOE data to slave %u...\n", + request->slave->ring_position); + + fsm->foe_request = &request->req; + fsm->slave = slave; + fsm->state = ec_fsm_master_state_foe_request; + ec_fsm_foe_transfer(&fsm->fsm_foe, slave, &request->req); + //(&fsm->fsm_foe, request->slave, request->offset, request->words); + ec_fsm_foe_exec(&fsm->fsm_foe); + return 1; + } + + return 0; +} + +/*****************************************************************************/ + /** Master action: IDLE. * * Does secondary work. @@ -659,8 +707,9 @@ ) { ec_master_t *master = fsm->master; +#ifdef EC_EOE ec_slave_t *slave = fsm->slave; - +#endif if (ec_fsm_slave_scan_exec(&fsm->fsm_slave_scan)) return; @@ -778,7 +827,7 @@ slave->sii.alias = EC_READ_U16(request->words + 4); } // TODO: Evaluate other SII contents! - + request->state = EC_REQUEST_SUCCESS; wake_up(&master->sii_queue); @@ -791,6 +840,40 @@ /*****************************************************************************/ +/** Master state: WRITE FOE. + */ +void ec_fsm_master_state_foe_request( + ec_fsm_master_t *fsm /**< Master state machine. */ + ) +{ + ec_master_t *master = fsm->master; + ec_foe_request_t *request = fsm->foe_request; + ec_slave_t *slave = fsm->slave; + + if (ec_fsm_foe_exec(&fsm->fsm_foe)) return; + + if (!ec_fsm_foe_success(&fsm->fsm_foe)) { + EC_ERR("Failed to handle FOE request to slave %u.\n", + slave->ring_position); + request->state = EC_REQUEST_FAILURE; + wake_up(&master->foe_queue); + ec_fsm_master_restart(fsm); + return; + } + + // finished writing FOE + if (master->debug_level) + EC_DBG("Finished writing %u words of FOE data to slave %u.\n", + request->data_size, slave->ring_position); + + request->state = EC_REQUEST_SUCCESS; + wake_up(&master->foe_queue); + + ec_fsm_master_restart(fsm); +} + +/*****************************************************************************/ + /** Master state: SDO DICTIONARY. */ void ec_fsm_master_state_sdo_dictionary( @@ -848,7 +931,7 @@ return; } - // SDO request finished + // SDO request finished request->state = EC_REQUEST_SUCCESS; wake_up(&master->sdo_queue); diff -r c55ebaa206f8 -r 11ec009e145d master/fsm_master.h --- a/master/fsm_master.h Mon Jan 19 10:17:21 2009 +0000 +++ b/master/fsm_master.h Mon Jan 19 10:18:41 2009 +0000 @@ -38,10 +38,12 @@ #include "globals.h" #include "datagram.h" +#include "foe_request.h" #include "sdo_request.h" #include "fsm_slave_config.h" #include "fsm_slave_scan.h" #include "fsm_pdo.h" +#include "fsm_foe.h" /*****************************************************************************/ @@ -68,6 +70,16 @@ /*****************************************************************************/ +/** FoE write request. + */ +typedef struct { + struct list_head list; /**< List head. */ + ec_slave_t *slave; /**< EtherCAT slave. */ + ec_foe_request_t req; /**< FoE request. */ +} ec_master_foe_request_t; + +/*****************************************************************************/ + typedef struct ec_fsm_master ec_fsm_master_t; /**< \see ec_fsm_master */ /** Finite state machine of an EtherCAT master. @@ -87,6 +99,8 @@ ec_sii_write_request_t *sii_request; /**< SII write request */ off_t sii_index; /**< index to SII write request data */ ec_sdo_request_t *sdo_request; /**< SDO request to process. */ + ec_foe_request_t *foe_request; /**< FoE request to process. */ + off_t foe_index; /**< index to FoE write request data */ ec_fsm_coe_t fsm_coe; /**< CoE state machine */ ec_fsm_pdo_t fsm_pdo; /**< PDO configuration state machine. */ @@ -94,6 +108,7 @@ ec_fsm_slave_config_t fsm_slave_config; /**< slave state machine */ ec_fsm_slave_scan_t fsm_slave_scan; /**< slave state machine */ ec_fsm_sii_t fsm_sii; /**< SII state machine */ + ec_fsm_foe_t fsm_foe; /**< FoE state machine */ }; /*****************************************************************************/ diff -r c55ebaa206f8 -r 11ec009e145d master/ioctl.h --- a/master/ioctl.h Mon Jan 19 10:17:21 2009 +0000 +++ b/master/ioctl.h Mon Jan 19 10:18:41 2009 +0000 @@ -69,6 +69,8 @@ #define EC_IOCTL_CONFIG_PDO EC_IOWR(0x11, ec_ioctl_config_pdo_t) #define EC_IOCTL_CONFIG_PDO_ENTRY EC_IOWR(0x12, ec_ioctl_config_pdo_entry_t) #define EC_IOCTL_CONFIG_SDO EC_IOWR(0x13, ec_ioctl_config_sdo_t) +#define EC_IOCTL_SLAVE_FOE_READ EC_IOWR(0x14, ec_ioctl_slave_foe_t) +#define EC_IOCTL_SLAVE_FOE_WRITE EC_IOW(0x15, ec_ioctl_slave_foe_t) #define EC_IOCTL_STRING_SIZE 64 @@ -342,6 +344,21 @@ /*****************************************************************************/ +typedef struct { + // inputs + uint16_t slave_position; + uint16_t offset; + uint32_t buffer_size; + uint8_t *buffer; + + // outputs + uint32_t data_size; + uint32_t abort_code; + char file_name[32]; +} ec_ioctl_slave_foe_t; + +/*****************************************************************************/ + /** \endcond */ #endif diff -r c55ebaa206f8 -r 11ec009e145d master/master.c --- a/master/master.c Mon Jan 19 10:17:21 2009 +0000 +++ b/master/master.c Mon Jan 19 10:18:41 2009 +0000 @@ -166,6 +166,9 @@ INIT_LIST_HEAD(&master->slave_sdo_requests); init_waitqueue_head(&master->sdo_queue); + INIT_LIST_HEAD(&master->foe_requests); + init_waitqueue_head(&master->foe_queue); + // init devices if (ec_device_init(&master->main_device, master)) goto out_return; diff -r c55ebaa206f8 -r 11ec009e145d master/master.h --- a/master/master.h Mon Jan 19 10:17:21 2009 +0000 +++ b/master/master.h Mon Jan 19 10:18:41 2009 +0000 @@ -151,6 +151,10 @@ struct list_head slave_sdo_requests; /**< SDO access requests. */ wait_queue_head_t sdo_queue; /**< Wait queue for SDO access requests from user space. */ + struct list_head foe_requests; /**< FoE write requests. */ + wait_queue_head_t foe_queue; /**< Wait queue for FoE + write requests from user space. */ + }; /*****************************************************************************/ diff -r c55ebaa206f8 -r 11ec009e145d tool/Command.cpp --- a/tool/Command.cpp Mon Jan 19 10:17:21 2009 +0000 +++ b/tool/Command.cpp Mon Jan 19 10:18:41 2009 +0000 @@ -63,6 +63,13 @@ force = f; }; +/*****************************************************************************/ + +void Command::setOutputFile(const string &f) +{ + outputFile = f; +}; + /****************************************************************************/ bool Command::matchesSubstr(const string &cmd) const diff -r c55ebaa206f8 -r 11ec009e145d tool/Command.h --- a/tool/Command.h Mon Jan 19 10:17:21 2009 +0000 +++ b/tool/Command.h Mon Jan 19 10:18:41 2009 +0000 @@ -70,6 +70,8 @@ const string &getDataType() const; void setForce(bool); bool getForce() const; + void setOutputFile(const string &); + const string &getOutputFile() const; bool matchesSubstr(const string &) const; bool matchesAbbrev(const string &) const; @@ -106,6 +108,7 @@ int domain; string dataType; bool force; + string outputFile; Command(); }; @@ -168,4 +171,11 @@ /****************************************************************************/ +inline const string &Command::getOutputFile() const +{ + return outputFile; +} + +/****************************************************************************/ + #endif diff -r c55ebaa206f8 -r 11ec009e145d tool/CommandFoeRead.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tool/CommandFoeRead.cpp Mon Jan 19 10:18:41 2009 +0000 @@ -0,0 +1,98 @@ +/***************************************************************************** + * + * $Id:$ + * + ****************************************************************************/ + +#include +#include +using namespace std; + +#include "CommandFoeRead.h" +#include "byteorder.h" + +/*****************************************************************************/ + +CommandFoeRead::CommandFoeRead(): + FoeCommand("foe_read", "Read a file from a slave via FoE.") +{ +} + +/*****************************************************************************/ + +string CommandFoeRead::helpString() const +{ + stringstream str; + + str << getName() << " [OPTIONS] " << endl + << endl + << getBriefDescription() << endl + << endl + << "This command requires a single slave to be selected." << endl + << endl + << "Arguments:" << endl + << " SOURCEFILE is the name of the source file on the slave." << endl + << endl + << "Command-specific options:" << endl + << " --output-file -o Local target filename. If" << endl + << " '-' (default), data are" << endl + << " printed to stdout." << endl + << " --alias -a " << endl + << " --position -p Slave selection. See the help" << endl + << " of the 'slaves' command." << endl + << endl + << numericInfo(); + + return str.str(); +} + +/****************************************************************************/ + +void CommandFoeRead::execute(MasterDevice &m, const StringVector &args) +{ + SlaveList slaves; + ec_ioctl_slave_t *slave; + ec_ioctl_slave_foe_t data; + unsigned int i; + stringstream err; + + if (args.size() != 1) { + err << "'" << getName() << "' takes exactly one argument!"; + throwInvalidUsageException(err); + } + + m.open(MasterDevice::Read); + slaves = selectedSlaves(m); + + if (slaves.size() != 1) { + throwSingleSlaveRequired(slaves.size()); + } + slave = &slaves.front(); + data.slave_position = slave->position; + + /* FIXME: No good idea to have a fixed buffer size. + * Read in chunks and fill a buffer instead. + */ + data.offset = 0; + data.buffer_size = 0x8800; + data.buffer = new uint8_t[data.buffer_size]; + + strncpy(data.file_name, args[0].c_str(), sizeof(data.file_name)); + + try { + m.readFoe(&data); + } catch (MasterDeviceException &e) { + delete [] data.buffer; + throw e; + } + + // TODO --output-file + for (i = 0; i < data.data_size; i++) { + uint8_t *w = data.buffer + i; + cout << *(uint8_t *) w ; + } + + delete [] data.buffer; +} + +/*****************************************************************************/ diff -r c55ebaa206f8 -r 11ec009e145d tool/CommandFoeRead.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tool/CommandFoeRead.h Mon Jan 19 10:18:41 2009 +0000 @@ -0,0 +1,26 @@ +/***************************************************************************** + * + * $Id:$ + * + ****************************************************************************/ + +#ifndef __COMMANDFOEREAD_H__ +#define __COMMANDFOEREAD_H__ + +#include "FoeCommand.h" + +/****************************************************************************/ + +class CommandFoeRead: + public FoeCommand +{ + public: + CommandFoeRead(); + + string helpString() const; + void execute(MasterDevice &, const StringVector &); +}; + +/****************************************************************************/ + +#endif diff -r c55ebaa206f8 -r 11ec009e145d tool/CommandFoeWrite.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tool/CommandFoeWrite.cpp Mon Jan 19 10:18:41 2009 +0000 @@ -0,0 +1,166 @@ +/***************************************************************************** + * + * $Id:$ + * + ****************************************************************************/ + +#include // basename() + +#include +#include +#include +using namespace std; + +#include "CommandFoeWrite.h" +#include "byteorder.h" + +/*****************************************************************************/ + +CommandFoeWrite::CommandFoeWrite(): + FoeCommand("foe_write", "Store a file on a slave via FoE.") +{ +} + +/*****************************************************************************/ + +string CommandFoeWrite::helpString() const +{ + stringstream str; + + str << getName() << " [OPTIONS] " << endl + << endl + << getBriefDescription() << endl + << endl + << "This command requires a single slave to be selected." << endl + << endl + << "Arguments:" << endl + << " FILENAME can either be a path to a file, or '-'. In" << endl + << " the latter case, data are read from stdin and" << endl + << " the --output-file option has to be specified." << endl + << endl + << "Command-specific options:" << endl + << " --output-file -o Target filename on the slave." << endl + << " If the FILENAME argument is" << endl + << " '-', this is mandatory." << endl + << " Otherwise, the basename() of" << endl + << " FILENAME is used by default." << endl + << " --alias -a " << endl + << " --position -p Slave selection. See the help" << endl + << " of the 'slaves' command." << endl + << endl + << numericInfo(); + + return str.str(); +} + +/****************************************************************************/ + +void CommandFoeWrite::execute(MasterDevice &m, const StringVector &args) +{ + stringstream err; + ec_ioctl_slave_foe_t data; + ifstream file; + SlaveList slaves; + string storeFileName; + + if (args.size() != 1) { + err << "'" << getName() << "' takes exactly one argument!"; + throwInvalidUsageException(err); + } + + if (args[0] == "-") { + loadFoeData(&data, cin); + if (getOutputFile().empty()) { + err << "Please specify a filename for the slave side" + << " with --output-file!"; + throwCommandException(err); + } else { + storeFileName = getOutputFile(); + } + } else { + file.open(args[0].c_str(), ifstream::in | ifstream::binary); + if (file.fail()) { + err << "Failed to open '" << args[0] << "'!"; + throwCommandException(err); + } + loadFoeData(&data, file); + file.close(); + if (getOutputFile().empty()) { + char *cpy = strdup(args[0].c_str()); // basename can modify + // the string contents + storeFileName = basename(cpy); + free(cpy); + } else { + storeFileName = getOutputFile(); + } + } + + try { + m.open(MasterDevice::ReadWrite); + } catch (MasterDeviceException &e) { + if (data.buffer_size) + delete [] data.buffer; + throw e; + } + + slaves = selectedSlaves(m); + if (slaves.size() != 1) { + if (data.buffer_size) + delete [] data.buffer; + throwSingleSlaveRequired(slaves.size()); + } + data.slave_position = slaves.front().position; + + // write data via foe to the slave + data.offset = 0; + strncpy(data.file_name, storeFileName.c_str(), sizeof(data.file_name)); + + try { + m.writeFoe(&data); + } catch (MasterDeviceException &e) { + if (data.buffer_size) + delete [] data.buffer; + if (data.abort_code) { + err << "Failed to write via FoE: " + << errorString(data.abort_code); + throwCommandException(err); + } else { + throw e; + } + } + + if (getVerbosity() == Verbose) { + cerr << "FoE writing finished." << endl; + } + + if (data.buffer_size) + delete [] data.buffer; +} + +/*****************************************************************************/ + +void CommandFoeWrite::loadFoeData( + ec_ioctl_slave_foe_t *data, + const istream &in + ) +{ + stringstream err; + ostringstream tmp; + + tmp << in.rdbuf(); + string const &contents = tmp.str(); + + if (getVerbosity() == Verbose) { + cerr << "Read " << contents.size() << " bytes of FoE data." << endl; + } + + data->buffer_size = contents.size(); + + if (data->buffer_size) { + // allocate buffer and read file into buffer + data->buffer = new uint8_t[data->buffer_size]; + contents.copy((char *) data->buffer, contents.size()); + } +} + +/*****************************************************************************/ diff -r c55ebaa206f8 -r 11ec009e145d tool/CommandFoeWrite.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tool/CommandFoeWrite.h Mon Jan 19 10:18:41 2009 +0000 @@ -0,0 +1,29 @@ +/***************************************************************************** + * + * $Id:$ + * + ****************************************************************************/ + +#ifndef __COMMANDFOEWRITE_H__ +#define __COMMANDFOEWRITE_H__ + +#include "FoeCommand.h" + +/****************************************************************************/ + +class CommandFoeWrite: + public FoeCommand +{ + public: + CommandFoeWrite(); + + string helpString() const; + void execute(MasterDevice &, const StringVector &); + + protected: + void loadFoeData(ec_ioctl_slave_foe_t *, const istream &); +}; + +/****************************************************************************/ + +#endif diff -r c55ebaa206f8 -r 11ec009e145d tool/FoeCommand.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tool/FoeCommand.cpp Mon Jan 19 10:18:41 2009 +0000 @@ -0,0 +1,59 @@ +/***************************************************************************** + * + * $Id$ + * + ****************************************************************************/ + +#include "FoeCommand.h" +#include "foe.h" + +/*****************************************************************************/ + +FoeCommand::FoeCommand(const string &name, const string &briefDesc): + Command(name, briefDesc) +{ +} + +/****************************************************************************/ + +std::string FoeCommand::errorString(int abort_code) +{ + switch (abort_code) { + case FOE_BUSY: + return "FOE_BUSY"; + case FOE_READY: + return "FOE_READY"; + case FOE_IDLE: + return "FOE_IDLE"; + case FOE_WC_ERROR: + return "FOE_WC_ERROR"; + case FOE_RECEIVE_ERROR: + return "FOE_RECEIVE_ERROR"; + case FOE_PROT_ERROR: + return "FOE_PROT_ERROR"; + case FOE_NODATA_ERROR: + return "FOE_NODATA_ERROR"; + case FOE_PACKETNO_ERROR: + return "FOE_PACKETNO_ERROR"; + case FOE_OPMODE_ERROR: + return "FOE_OPMODE_ERROR"; + case FOE_TIMEOUT_ERROR: + return "FOE_TIMEOUT_ERROR"; + case FOE_SEND_RX_DATA_ERROR: + return "FOE_SEND_RX_DATA_ERROR"; + case FOE_RX_DATA_ACK_ERROR: + return "FOE_RX_DATA_ACK_ERROR"; + case FOE_ACK_ERROR: + return "FOE_ACK_ERROR"; + case FOE_MBOX_FETCH_ERROR: + return "FOE_MBOX_FETCH_ERROR"; + case FOE_READ_NODATA_ERROR: + return "FOE_READ_NODATA_ERROR"; + case FOE_MBOX_PROT_ERROR: + return "FOE_MBOX_PROT_ERROR"; + default: + return "???"; + } +} + +/****************************************************************************/ diff -r c55ebaa206f8 -r 11ec009e145d tool/FoeCommand.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tool/FoeCommand.h Mon Jan 19 10:18:41 2009 +0000 @@ -0,0 +1,26 @@ +/***************************************************************************** + * + * $Id$ + * + ****************************************************************************/ + +#ifndef __FOECOMMAND_H__ +#define __FOECOMMAND_H__ + +#include "Command.h" + +/****************************************************************************/ + +class FoeCommand: + public Command +{ + public: + FoeCommand(const string &, const string &); + + protected: + static std::string errorString(int); +}; + +/****************************************************************************/ + +#endif diff -r c55ebaa206f8 -r 11ec009e145d tool/Makefile.am --- a/tool/Makefile.am Mon Jan 19 10:17:21 2009 +0000 +++ b/tool/Makefile.am Mon Jan 19 10:18:41 2009 +0000 @@ -36,6 +36,8 @@ CommandDebug.cpp \ CommandDomains.cpp \ CommandDownload.cpp \ + CommandFoeRead.cpp \ + CommandFoeWrite.cpp \ CommandMaster.cpp \ CommandPdos.cpp \ CommandSdos.cpp \ @@ -46,6 +48,7 @@ CommandUpload.cpp \ CommandVersion.cpp \ CommandXml.cpp \ + FoeCommand.cpp \ MasterDevice.cpp \ SdoCommand.cpp \ main.cpp \ @@ -59,6 +62,8 @@ CommandDebug.h \ CommandDomains.h \ CommandDownload.h \ + CommandFoeRead.h \ + CommandFoeWrite.h \ CommandMaster.h \ CommandPdos.h \ CommandSdos.h \ @@ -69,7 +74,8 @@ CommandUpload.h \ CommandVersion.h \ CommandXml.h \ - MasterDevice.h \ + FoeCommand.h \ + MasterDevice.h \ SdoCommand.h \ byteorder.h \ sii_crc.h diff -r c55ebaa206f8 -r 11ec009e145d tool/MasterDevice.cpp --- a/tool/MasterDevice.cpp Mon Jan 19 10:17:21 2009 +0000 +++ b/tool/MasterDevice.cpp Mon Jan 19 10:18:41 2009 +0000 @@ -346,6 +346,32 @@ /****************************************************************************/ +void MasterDevice::readFoe( + ec_ioctl_slave_foe_t *data + ) +{ + if (ioctl(fd, EC_IOCTL_SLAVE_FOE_READ, data) < 0) { + stringstream err; + err << "Failed to read via FoE: " << strerror(errno); + throw MasterDeviceException(err); + } +} + +/****************************************************************************/ + +void MasterDevice::writeFoe( + ec_ioctl_slave_foe_t *data + ) +{ + if (ioctl(fd, EC_IOCTL_SLAVE_FOE_WRITE, data) < 0) { + stringstream err; + err << "Failed to write via FoE: " << strerror(errno); + throw MasterDeviceException(err); + } +} + +/****************************************************************************/ + void MasterDevice::setDebug(unsigned int debugLevel) { if (ioctl(fd, EC_IOCTL_MASTER_DEBUG, debugLevel) < 0) { diff -r c55ebaa206f8 -r 11ec009e145d tool/MasterDevice.h --- a/tool/MasterDevice.h Mon Jan 19 10:17:21 2009 +0000 +++ b/tool/MasterDevice.h Mon Jan 19 10:18:41 2009 +0000 @@ -90,6 +90,8 @@ void sdoDownload(ec_ioctl_slave_sdo_download_t *); void sdoUpload(ec_ioctl_slave_sdo_upload_t *); void requestState(uint16_t, uint8_t); + void readFoe(ec_ioctl_slave_foe_t *); + void writeFoe(ec_ioctl_slave_foe_t *); private: unsigned int index; diff -r c55ebaa206f8 -r 11ec009e145d tool/main.cpp --- a/tool/main.cpp Mon Jan 19 10:17:21 2009 +0000 +++ b/tool/main.cpp Mon Jan 19 10:18:41 2009 +0000 @@ -18,6 +18,8 @@ #include "CommandDebug.h" #include "CommandDomains.h" #include "CommandDownload.h" +#include "CommandFoeRead.h" +#include "CommandFoeWrite.h" #include "CommandMaster.h" #include "CommandPdos.h" #include "CommandSdos.h" @@ -49,6 +51,7 @@ Command::Verbosity verbosity = Command::Normal; bool force = false; bool helpRequested = false; +string outputFile; /*****************************************************************************/ @@ -101,21 +104,22 @@ stringstream str; static struct option longOptions[] = { - //name, has_arg, flag, val - {"master", required_argument, NULL, 'm'}, - {"alias", required_argument, NULL, 'a'}, - {"position", required_argument, NULL, 'p'}, - {"domain", required_argument, NULL, 'd'}, - {"type", required_argument, NULL, 't'}, - {"force", no_argument, NULL, 'f'}, - {"quiet", no_argument, NULL, 'q'}, - {"verbose", no_argument, NULL, 'v'}, - {"help", no_argument, NULL, 'h'}, + //name, has_arg, flag, val + {"master", required_argument, NULL, 'm'}, + {"alias", required_argument, NULL, 'a'}, + {"position", required_argument, NULL, 'p'}, + {"domain", required_argument, NULL, 'd'}, + {"type", required_argument, NULL, 't'}, + {"output-file", required_argument, NULL, 'o'}, + {"force", no_argument, NULL, 'f'}, + {"quiet", no_argument, NULL, 'q'}, + {"verbose", no_argument, NULL, 'v'}, + {"help", no_argument, NULL, 'h'}, {} }; do { - c = getopt_long(argc, argv, "m:a:p:d:t:fqvh", longOptions, NULL); + c = getopt_long(argc, argv, "m:a:p:d:t:o:fqvh", longOptions, NULL); switch (c) { case 'm': @@ -175,6 +179,10 @@ dataTypeStr = optarg; break; + case 'o': + outputFile = optarg; + break; + case 'f': force = true; break; @@ -262,6 +270,8 @@ commandList.push_back(new CommandDebug()); commandList.push_back(new CommandDomains()); commandList.push_back(new CommandDownload()); + commandList.push_back(new CommandFoeRead()); + commandList.push_back(new CommandFoeWrite()); commandList.push_back(new CommandMaster()); commandList.push_back(new CommandPdos()); commandList.push_back(new CommandSdos()); @@ -288,6 +298,7 @@ cmd->setPosition(slavePosition); cmd->setDomain(domainIndex); cmd->setDataType(dataTypeStr); + cmd->setOutputFile(outputFile); cmd->setForce(force); cmd->execute(masterDev, commandArgs); } catch (InvalidUsageException &e) {