# HG changeset patch # User Florian Pose # Date 1415799737 -3600 # Node ID 0e145bb058590f72f43c9e68be8f3e395e56791d # Parent d71acfbd73194d6491466155d5e38638dd89a367 Implemented EoE Set IP parameter request via command-line tool. diff -r d71acfbd7319 -r 0e145bb05859 master/Kbuild.in --- a/master/Kbuild.in Thu Nov 06 08:55:35 2014 +0100 +++ b/master/Kbuild.in Wed Nov 12 14:42:17 2014 +0100 @@ -40,10 +40,12 @@ datagram_pair.o \ device.o \ domain.o \ + eoe_request.o \ fmmu_config.o \ foe_request.o \ fsm_change.o \ fsm_coe.o \ + fsm_eoe.o \ fsm_foe.o \ fsm_master.o \ fsm_pdo.o \ diff -r d71acfbd7319 -r 0e145bb05859 master/Makefile.am --- a/master/Makefile.am Thu Nov 06 08:55:35 2014 +0100 +++ b/master/Makefile.am Wed Nov 12 14:42:17 2014 +0100 @@ -37,12 +37,14 @@ device.c device.h \ domain.c domain.h \ doxygen.c \ + eoe_request.c eoe_request.h \ ethernet.c ethernet.h \ fmmu_config.c fmmu_config.h \ foe.h \ foe_request.c foe_request.h \ fsm_change.c fsm_change.h \ fsm_coe.c fsm_coe.h \ + fsm_eoe.c fsm_eoe.h \ fsm_foe.c fsm_foe.h \ fsm_master.c fsm_master.h \ fsm_pdo.c fsm_pdo.h \ diff -r d71acfbd7319 -r 0e145bb05859 master/eoe_request.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/master/eoe_request.c Wed Nov 12 14:42:17 2014 +0100 @@ -0,0 +1,71 @@ +/****************************************************************************** + * + * $Id$ + * + * Copyright (C) 2006-2014 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 + * + * --- + * + * The license mentioned above concerns the source code only. Using the + * EtherCAT technology and brand is only permitted in compliance with the + * industrial property and similar rights of Beckhoff Automation GmbH. + * + *****************************************************************************/ + +/** \file + * Ethernet-over-EtherCAT request functions. + */ + +/*****************************************************************************/ + +#include +#include +#include + +#include "eoe_request.h" + +/*****************************************************************************/ + +/** EoE request constructor. + */ +void ec_eoe_request_init( + ec_eoe_request_t *req /**< EoE request. */ + ) +{ + INIT_LIST_HEAD(&req->list); + req->state = EC_INT_REQUEST_INIT; + req->jiffies_sent = 0U; + + req->mac_address_included = 0; + req->ip_address_included = 0; + req->subnet_mask_included = 0; + req->gateway_included = 0; + req->dns_included = 0; + req->name_included = 0; + + memset(req->mac_address, 0x00, ETH_ALEN); + req->ip_address = 0; + req->subnet_mask = 0; + req->gateway = 0; + req->dns = 0; + req->name[0] = 0x00; + + req->result = 0x0000; +} + +/*****************************************************************************/ diff -r d71acfbd7319 -r 0e145bb05859 master/eoe_request.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/master/eoe_request.h Wed Nov 12 14:42:17 2014 +0100 @@ -0,0 +1,77 @@ +/****************************************************************************** + * + * $Id$ + * + * Copyright (C) 2006-2014 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 + * + * --- + * + * The license mentioned above concerns the source code only. Using the + * EtherCAT technology and brand is only permitted in compliance with the + * industrial property and similar rights of Beckhoff Automation GmbH. + * + *****************************************************************************/ + +/** + \file + EtherCAT EoE request structure. +*/ + +/*****************************************************************************/ + +#ifndef __EC_EOE_REQUEST_H__ +#define __EC_EOE_REQUEST_H__ + +#include +#include // ETH_ALEN + +#include "globals.h" + +/*****************************************************************************/ + +/** Ethernet-over-EtherCAT set IP parameter request. + */ +typedef struct { + struct list_head list; /**< List item. */ + ec_internal_request_state_t state; /**< Request state. */ + unsigned long jiffies_sent; /**< Jiffies, when the request was sent. */ + + uint8_t mac_address_included; + uint8_t ip_address_included; + uint8_t subnet_mask_included; + uint8_t gateway_included; + uint8_t dns_included; + uint8_t name_included; + + unsigned char mac_address[ETH_ALEN]; + uint32_t ip_address; + uint32_t subnet_mask; + uint32_t gateway; + uint32_t dns; + char name[EC_MAX_HOSTNAME_SIZE]; + + uint16_t result; +} ec_eoe_request_t; + +/*****************************************************************************/ + +void ec_eoe_request_init(ec_eoe_request_t *); + +/*****************************************************************************/ + +#endif diff -r d71acfbd7319 -r 0e145bb05859 master/fsm_eoe.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/master/fsm_eoe.c Wed Nov 12 14:42:17 2014 +0100 @@ -0,0 +1,485 @@ +/****************************************************************************** + * + * $Id$ + * + * Copyright (C) 2006-2014 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 + * + * --- + * + * The license mentioned above concerns the source code only. Using the + * EtherCAT technology and brand is only permitted in compliance with the + * industrial property and similar rights of Beckhoff Automation GmbH. + * + *****************************************************************************/ + +/** + \file + EtherCAT EoE state machines. +*/ + +/*****************************************************************************/ + +#include "globals.h" +#include "master.h" +#include "mailbox.h" +#include "fsm_eoe.h" + +/*****************************************************************************/ + +/** Maximum time to wait for a set IP parameter response. + */ +#define EC_EOE_RESPONSE_TIMEOUT 3000 // [ms] + +/*****************************************************************************/ + +void ec_fsm_eoe_set_ip_start(ec_fsm_eoe_t *, ec_datagram_t *); +void ec_fsm_eoe_set_ip_request(ec_fsm_eoe_t *, ec_datagram_t *); +void ec_fsm_eoe_set_ip_check(ec_fsm_eoe_t *, ec_datagram_t *); +void ec_fsm_eoe_set_ip_response(ec_fsm_eoe_t *, ec_datagram_t *); + +void ec_fsm_eoe_end(ec_fsm_eoe_t *, ec_datagram_t *); +void ec_fsm_eoe_error(ec_fsm_eoe_t *, ec_datagram_t *); + +/*****************************************************************************/ + +/** Constructor. + */ +void ec_fsm_eoe_init( + ec_fsm_eoe_t *fsm /**< finite state machine */ + ) +{ + fsm->slave = NULL; + fsm->retries = 0; + fsm->state = NULL; + fsm->datagram = NULL; + fsm->jiffies_start = 0; + fsm->request = NULL; +} + +/*****************************************************************************/ + +/** Destructor. + */ +void ec_fsm_eoe_clear( + ec_fsm_eoe_t *fsm /**< finite state machine */ + ) +{ +} + +/*****************************************************************************/ + +/** Starts to set the EoE IP partameters of a slave. + */ +void ec_fsm_eoe_set_ip_param( + ec_fsm_eoe_t *fsm, /**< State machine. */ + ec_slave_t *slave, /**< EtherCAT slave. */ + ec_eoe_request_t *request /**< EoE request. */ + ) +{ + fsm->slave = slave; + fsm->request = request; + fsm->state = ec_fsm_eoe_set_ip_start; +} + +/*****************************************************************************/ + +/** Executes the current state of the state machine. + * + * \return 1 if the datagram was used, else 0. + */ +int ec_fsm_eoe_exec( + ec_fsm_eoe_t *fsm, /**< finite state machine */ + ec_datagram_t *datagram /**< Datagram to use. */ + ) +{ + int datagram_used = 0; + + if (fsm->datagram && + (fsm->datagram->state == EC_DATAGRAM_INIT || + fsm->datagram->state == EC_DATAGRAM_QUEUED || + fsm->datagram->state == EC_DATAGRAM_SENT)) { + // datagram not received yet + return datagram_used; + } + + fsm->state(fsm, datagram); + + datagram_used = + fsm->state != ec_fsm_eoe_end && fsm->state != ec_fsm_eoe_error; + + if (datagram_used) { + fsm->datagram = datagram; + } else { + fsm->datagram = NULL; + } + + return datagram_used; +} + +/*****************************************************************************/ + +/** Returns, if the state machine terminated with success. + * + * \return non-zero if successful. + */ +int ec_fsm_eoe_success(const ec_fsm_eoe_t *fsm /**< Finite state machine */) +{ + return fsm->state == ec_fsm_eoe_end; +} + +/****************************************************************************** + * EoE set IP parameter state machine + *****************************************************************************/ + +/** Prepare a set IP parameters operation. + * + * \return 0 on success, otherwise a negative error code. + */ +int ec_fsm_eoe_prepare_set( + ec_fsm_eoe_t *fsm, /**< finite state machine */ + ec_datagram_t *datagram /**< Datagram to use. */ + ) +{ + uint8_t *data, *cur; + ec_slave_t *slave = fsm->slave; + ec_master_t *master = slave->master; + ec_eoe_request_t *req = fsm->request; + size_t size = 8; + + if (req->mac_address_included) { + size += ETH_ALEN; + } + + if (req->ip_address_included) { + size += 4; + } + + if (req->subnet_mask_included) { + size += 4; + } + + if (req->gateway_included) { + size += 4; + } + + if (req->dns_included) { + size += 4; + } + + if (req->name_included) { + size += EC_MAX_HOSTNAME_SIZE; + } + + data = ec_slave_mbox_prepare_send(slave, datagram, EC_MBOX_TYPE_EOE, + size); + if (IS_ERR(data)) { + return PTR_ERR(data); + } + + EC_WRITE_U8(data, EC_EOE_FRAMETYPE_SET_IP_REQ); // Set IP parameter req. + EC_WRITE_U8(data + 1, 0x01); // last fragment, no timestamps + EC_WRITE_U16(data + 2, 0x0000); // fragment no., offset, frame no. + + EC_WRITE_U32(data + 4, + ((req->mac_address_included != 0) << 0) | + ((req->ip_address_included != 0) << 1) | + ((req->subnet_mask_included != 0) << 2) | + ((req->gateway_included != 0) << 3) | + ((req->dns_included != 0) << 4) | + ((req->name_included != 0) << 5) + ); + + cur = data + 8; + + if (req->mac_address_included) { + memcpy(cur, req->mac_address, ETH_ALEN); + cur += ETH_ALEN; + } + + if (req->ip_address_included) { + memcpy(cur, &req->ip_address, 4); + cur += 4; + } + + if (req->subnet_mask_included) { + memcpy(cur, &req->subnet_mask, 4); + cur += 4; + } + + if (req->gateway_included) { + memcpy(cur, &req->gateway, 4); + cur += 4; + } + + if (req->dns_included) { + memcpy(cur, &req->dns, 4); + cur += 4; + } + + if (req->name_included) { + memcpy(cur, req->name, EC_MAX_HOSTNAME_SIZE); + cur += EC_MAX_HOSTNAME_SIZE; + } + + if (master->debug_level) { + EC_SLAVE_DBG(slave, 0, "Set IP parameter request:\n"); + ec_print_data(data, cur - data); + } + + fsm->request->jiffies_sent = jiffies; + + return 0; +} + +/*****************************************************************************/ + +/** EoE state: SET IP START. + */ +void ec_fsm_eoe_set_ip_start( + ec_fsm_eoe_t *fsm, /**< finite state machine */ + ec_datagram_t *datagram /**< Datagram to use. */ + ) +{ + ec_slave_t *slave = fsm->slave; + + EC_SLAVE_DBG(slave, 1, "Setting IP parameters.\n"); + + if (!(slave->sii.mailbox_protocols & EC_MBOX_EOE)) { + EC_SLAVE_ERR(slave, "Slave does not support EoE!\n"); + fsm->state = ec_fsm_eoe_error; + return; + } + + if (ec_fsm_eoe_prepare_set(fsm, datagram)) { + fsm->state = ec_fsm_eoe_error; + return; + } + + fsm->retries = EC_FSM_RETRIES; + fsm->state = ec_fsm_eoe_set_ip_request; +} + +/*****************************************************************************/ + +/** EoE state: SET IP REQUEST. + */ +void ec_fsm_eoe_set_ip_request( + ec_fsm_eoe_t *fsm, /**< finite state machine */ + ec_datagram_t *datagram /**< Datagram to use. */ + ) +{ + ec_slave_t *slave = fsm->slave; + + if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) { + if (ec_fsm_eoe_prepare_set(fsm, datagram)) { + fsm->state = ec_fsm_eoe_error; + } + return; + } + + if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) { + fsm->state = ec_fsm_eoe_error; + EC_SLAVE_ERR(slave, "Failed to receive EoE set IP parameter" + " request: "); + ec_datagram_print_state(fsm->datagram); + return; + } + + if (fsm->datagram->working_counter != 1) { + unsigned long diff_ms = + (jiffies - fsm->request->jiffies_sent) * 1000 / HZ; + + if (!fsm->datagram->working_counter) { + if (diff_ms < EC_EOE_RESPONSE_TIMEOUT) { + // no response; send request datagram again + if (ec_fsm_eoe_prepare_set(fsm, datagram)) { + fsm->state = ec_fsm_eoe_error; + } + return; + } + } + fsm->state = ec_fsm_eoe_error; + EC_SLAVE_ERR(slave, "Reception of EoE set IP parameter request" + " failed after %lu ms: ", diff_ms); + ec_datagram_print_wc_error(fsm->datagram); + return; + } + + fsm->jiffies_start = fsm->datagram->jiffies_sent; + ec_slave_mbox_prepare_check(slave, datagram); // can not fail. + fsm->retries = EC_FSM_RETRIES; + fsm->state = ec_fsm_eoe_set_ip_check; +} + +/*****************************************************************************/ + +/** EoE state: SET IP CHECK. + */ +void ec_fsm_eoe_set_ip_check( + ec_fsm_eoe_t *fsm, /**< finite state machine */ + ec_datagram_t *datagram /**< Datagram to use. */ + ) +{ + ec_slave_t *slave = fsm->slave; + + if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) { + ec_slave_mbox_prepare_check(slave, datagram); // can not fail. + return; + } + + if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) { + fsm->state = ec_fsm_eoe_error; + EC_SLAVE_ERR(slave, "Failed to receive EoE mailbox check datagram: "); + ec_datagram_print_state(fsm->datagram); + return; + } + + if (fsm->datagram->working_counter != 1) { + fsm->state = ec_fsm_eoe_error; + EC_SLAVE_ERR(slave, "Reception of EoE mailbox check" + " datagram failed: "); + ec_datagram_print_wc_error(fsm->datagram); + return; + } + + if (!ec_slave_mbox_check(fsm->datagram)) { + unsigned long diff_ms = + (fsm->datagram->jiffies_received - fsm->jiffies_start) * + 1000 / HZ; + if (diff_ms >= EC_EOE_RESPONSE_TIMEOUT) { + fsm->state = ec_fsm_eoe_error; + EC_SLAVE_ERR(slave, "Timeout after %lu ms while waiting for" + " set IP parameter response.\n", diff_ms); + 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_eoe_set_ip_response; +} + +/*****************************************************************************/ + +/** EoE state: SET IP RESPONSE. + */ +void ec_fsm_eoe_set_ip_response( + ec_fsm_eoe_t *fsm, /**< finite state machine */ + ec_datagram_t *datagram /**< Datagram to use. */ + ) +{ + ec_slave_t *slave = fsm->slave; + ec_master_t *master = slave->master; + uint8_t *data, mbox_prot, frame_type; + size_t rec_size; + ec_eoe_request_t *req = fsm->request; + + if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) { + ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail. + return; + } + + if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) { + fsm->state = ec_fsm_eoe_error; + EC_SLAVE_ERR(slave, "Failed to receive EoE read response datagram: "); + ec_datagram_print_state(fsm->datagram); + return; + } + + if (fsm->datagram->working_counter != 1) { + fsm->state = ec_fsm_eoe_error; + EC_SLAVE_ERR(slave, "Reception of EoE read response failed: "); + ec_datagram_print_wc_error(fsm->datagram); + return; + } + + data = ec_slave_mbox_fetch(slave, fsm->datagram, &mbox_prot, &rec_size); + if (IS_ERR(data)) { + fsm->state = ec_fsm_eoe_error; + return; + } + + if (master->debug_level) { + EC_SLAVE_DBG(slave, 0, "Set IP parameter response:\n"); + ec_print_data(data, rec_size); + } + + if (mbox_prot != EC_MBOX_TYPE_EOE) { + fsm->state = ec_fsm_eoe_error; + EC_SLAVE_ERR(slave, "Received mailbox protocol 0x%02X as response.\n", + mbox_prot); + return; + } + + if (rec_size < 4) { + fsm->state = ec_fsm_eoe_error; + EC_SLAVE_ERR(slave, "Received currupted EoE set IP parameter response" + " (%zu bytes)!\n", rec_size); + ec_print_data(data, rec_size); + return; + } + + frame_type = EC_READ_U8(data) & 0x0f; + + if (frame_type != EC_EOE_FRAMETYPE_SET_IP_RES) { + EC_SLAVE_ERR(slave, "Received no set IP parameter response" + " (frame type %x).\n", frame_type); + ec_print_data(data, rec_size); + fsm->state = ec_fsm_eoe_error; + return; + } + + req->result = EC_READ_U16(data + 2); + + if (req->result) { + fsm->state = ec_fsm_eoe_error; + EC_SLAVE_DBG(slave, 1, "EoE set IP parameters failed with result code" + " 0x%04X.\n", req->result); + } else { + fsm->state = ec_fsm_eoe_end; // success + } +} + +/*****************************************************************************/ + +/** State: ERROR. + */ +void ec_fsm_eoe_error( + ec_fsm_eoe_t *fsm, /**< finite state machine */ + ec_datagram_t *datagram /**< Datagram to use. */ + ) +{ +} + +/*****************************************************************************/ + +/** State: END. + */ +void ec_fsm_eoe_end( + ec_fsm_eoe_t *fsm, /**< finite state machine */ + ec_datagram_t *datagram /**< Datagram to use. */ + ) +{ +} + +/*****************************************************************************/ diff -r d71acfbd7319 -r 0e145bb05859 master/fsm_eoe.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/master/fsm_eoe.h Wed Nov 12 14:42:17 2014 +0100 @@ -0,0 +1,74 @@ +/***************************************************************************** + * + * $Id$ + * + * Copyright (C) 2006-2014 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 + * + * --- + * + * The license mentioned above concerns the source code only. Using the + * EtherCAT technology and brand is only permitted in compliance with the + * industrial property and similar rights of Beckhoff Automation GmbH. + * + ****************************************************************************/ + +/** + \file + EtherCAT EoE set IP parameter state machines. +*/ + +/****************************************************************************/ + +#ifndef __EC_FSM_EOE_H__ +#define __EC_FSM_EOE_H__ + +#include "globals.h" +#include "datagram.h" +#include "slave.h" +#include "eoe_request.h" + +/****************************************************************************/ + +typedef struct ec_fsm_eoe ec_fsm_eoe_t; /**< \see ec_fsm_eoe */ + +/** Finite state machines for the Ethernet over EtherCAT protocol. + */ +struct ec_fsm_eoe { + ec_slave_t *slave; /**< slave the FSM runs on */ + unsigned int retries; /**< retries upon datagram timeout */ + + void (*state)(ec_fsm_eoe_t *, ec_datagram_t *); /**< EoE state function */ + ec_datagram_t *datagram; /**< Datagram used in the previous step. */ + unsigned long jiffies_start; /**< Timestamp. */ + ec_eoe_request_t *request; /**< EoE request */ +}; + +/****************************************************************************/ + +void ec_fsm_eoe_init(ec_fsm_eoe_t *); +void ec_fsm_eoe_clear(ec_fsm_eoe_t *); + +void ec_fsm_eoe_set_ip_param(ec_fsm_eoe_t *, ec_slave_t *, + ec_eoe_request_t *); + +int ec_fsm_eoe_exec(ec_fsm_eoe_t *, ec_datagram_t *); +int ec_fsm_eoe_success(const ec_fsm_eoe_t *); + +/****************************************************************************/ + +#endif diff -r d71acfbd7319 -r 0e145bb05859 master/fsm_slave.c --- a/master/fsm_slave.c Thu Nov 06 08:55:35 2014 +0100 +++ b/master/fsm_slave.c Wed Nov 12 14:42:17 2014 +0100 @@ -52,6 +52,8 @@ void ec_fsm_slave_state_foe_request(ec_fsm_slave_t *, ec_datagram_t *); int ec_fsm_slave_action_process_soe(ec_fsm_slave_t *, ec_datagram_t *); void ec_fsm_slave_state_soe_request(ec_fsm_slave_t *, ec_datagram_t *); +int ec_fsm_slave_action_process_eoe(ec_fsm_slave_t *, ec_datagram_t *); +void ec_fsm_slave_state_eoe_request(ec_fsm_slave_t *, ec_datagram_t *); /*****************************************************************************/ @@ -71,11 +73,13 @@ fsm->reg_request = NULL; fsm->foe_request = NULL; fsm->soe_request = NULL; + fsm->eoe_request = NULL; // Init sub-state-machines ec_fsm_coe_init(&fsm->fsm_coe); ec_fsm_foe_init(&fsm->fsm_foe); ec_fsm_soe_init(&fsm->fsm_soe); + ec_fsm_eoe_init(&fsm->fsm_eoe); } /*****************************************************************************/ @@ -108,10 +112,16 @@ wake_up_all(&fsm->slave->master->request_queue); } + if (fsm->eoe_request) { + fsm->soe_request->state = EC_INT_REQUEST_FAILURE; + wake_up_all(&fsm->slave->master->request_queue); + } + // clear sub-state machines ec_fsm_coe_clear(&fsm->fsm_coe); ec_fsm_foe_clear(&fsm->fsm_foe); ec_fsm_soe_clear(&fsm->fsm_soe); + ec_fsm_eoe_clear(&fsm->fsm_eoe); } /*****************************************************************************/ @@ -210,6 +220,11 @@ if (ec_fsm_slave_action_process_soe(fsm, datagram)) { return; } + + // Check for pending EoE IP parameter requests + if (ec_fsm_slave_action_process_eoe(fsm, datagram)) { + return; + } } /*****************************************************************************/ @@ -240,7 +255,7 @@ request->state = EC_INT_REQUEST_FAILURE; wake_up_all(&slave->master->request_queue); fsm->state = ec_fsm_slave_state_idle; - return 1; + return 0; } if (slave->current_state == EC_SLAVE_STATE_INIT) { @@ -248,7 +263,7 @@ request->state = EC_INT_REQUEST_FAILURE; wake_up_all(&slave->master->request_queue); fsm->state = ec_fsm_slave_state_idle; - return 1; + return 0; } fsm->sdo_request = request; @@ -342,7 +357,7 @@ wake_up_all(&slave->master->request_queue); fsm->reg_request = NULL; fsm->state = ec_fsm_slave_state_idle; - return 1; + return 0; } // Found pending register request. Execute it! @@ -444,7 +459,7 @@ request->state = EC_INT_REQUEST_FAILURE; wake_up_all(&slave->master->request_queue); fsm->state = ec_fsm_slave_state_idle; - return 1; + return 0; } request->state = EC_INT_REQUEST_BUSY; @@ -521,7 +536,7 @@ req->state = EC_INT_REQUEST_FAILURE; wake_up_all(&slave->master->request_queue); fsm->state = ec_fsm_slave_state_idle; - return 1; + return 0; } if (slave->current_state == EC_SLAVE_STATE_INIT) { @@ -580,3 +595,85 @@ } /*****************************************************************************/ + +/** Check for pending EoE IP parameter requests and process one. + * + * \return non-zero, if a request is processed. + */ +int ec_fsm_slave_action_process_eoe( + ec_fsm_slave_t *fsm, /**< Slave state machine. */ + ec_datagram_t *datagram /**< Datagram to use. */ + ) +{ + ec_slave_t *slave = fsm->slave; + ec_eoe_request_t *request; + + if (list_empty(&slave->eoe_requests)) { + return 0; + } + + // take the first request to be processed + request = list_entry(slave->eoe_requests.next, ec_eoe_request_t, list); + list_del_init(&request->list); // dequeue + + if (slave->current_state & EC_SLAVE_STATE_ACK_ERR) { + EC_SLAVE_WARN(slave, "Aborting EoE request," + " slave has error flag set.\n"); + request->state = EC_INT_REQUEST_FAILURE; + wake_up_all(&slave->master->request_queue); + fsm->state = ec_fsm_slave_state_idle; + return 0; + } + + if (slave->current_state == EC_SLAVE_STATE_INIT) { + EC_SLAVE_WARN(slave, "Aborting EoE request, slave is in INIT.\n"); + request->state = EC_INT_REQUEST_FAILURE; + wake_up_all(&slave->master->request_queue); + fsm->state = ec_fsm_slave_state_idle; + return 0; + } + + fsm->eoe_request = request; + request->state = EC_INT_REQUEST_BUSY; + + // Found pending request. Execute it! + EC_SLAVE_DBG(slave, 1, "Processing EoE request...\n"); + + // Start EoE command + fsm->state = ec_fsm_slave_state_eoe_request; + ec_fsm_eoe_set_ip_param(&fsm->fsm_eoe, slave, request); + ec_fsm_eoe_exec(&fsm->fsm_eoe, datagram); // execute immediately + return 1; +} + +/*****************************************************************************/ + +/** Slave state: EOE_REQUEST. + */ +void ec_fsm_slave_state_eoe_request( + ec_fsm_slave_t *fsm, /**< Slave state machine. */ + ec_datagram_t *datagram /**< Datagram to use. */ + ) +{ + ec_slave_t *slave = fsm->slave; + ec_eoe_request_t *req = fsm->eoe_request; + + if (ec_fsm_eoe_exec(&fsm->fsm_eoe, datagram)) { + return; + } + + if (ec_fsm_eoe_success(&fsm->fsm_eoe)) { + req->state = EC_INT_REQUEST_SUCCESS; + EC_SLAVE_DBG(slave, 1, "Finished EoE request.\n"); + } + else { + req->state = EC_INT_REQUEST_FAILURE; + EC_SLAVE_ERR(slave, "Failed to process EoE request.\n"); + } + + wake_up_all(&slave->master->request_queue); + fsm->eoe_request = NULL; + fsm->state = ec_fsm_slave_state_ready; +} + +/*****************************************************************************/ diff -r d71acfbd7319 -r 0e145bb05859 master/fsm_slave.h --- a/master/fsm_slave.h Thu Nov 06 08:55:35 2014 +0100 +++ b/master/fsm_slave.h Wed Nov 12 14:42:17 2014 +0100 @@ -41,9 +41,11 @@ #include "datagram.h" #include "sdo_request.h" #include "reg_request.h" +#include "eoe_request.h" #include "fsm_coe.h" #include "fsm_foe.h" #include "fsm_soe.h" +#include "fsm_eoe.h" /*****************************************************************************/ @@ -62,10 +64,12 @@ ec_foe_request_t *foe_request; /**< FoE request to process. */ off_t foe_index; /**< Index to FoE write request data. */ ec_soe_request_t *soe_request; /**< SoE request to process. */ + ec_eoe_request_t *eoe_request; /**< SoE request to process. */ ec_fsm_coe_t fsm_coe; /**< CoE state machine. */ ec_fsm_foe_t fsm_foe; /**< FoE state machine. */ ec_fsm_soe_t fsm_soe; /**< SoE state machine. */ + ec_fsm_eoe_t fsm_eoe; /**< EoE state machine. */ }; /*****************************************************************************/ diff -r d71acfbd7319 -r 0e145bb05859 master/globals.h --- a/master/globals.h Thu Nov 06 08:55:35 2014 +0100 +++ b/master/globals.h Wed Nov 12 14:42:17 2014 +0100 @@ -115,6 +115,12 @@ **/ #define EC_DATAGRAM_NAME_SIZE 20 +/** Maximum hostname size. + * + * Used inside the EoE set IP parameter request. + */ +#define EC_MAX_HOSTNAME_SIZE 32 + /** Slave state mask. * * Apply this mask to a slave state byte to get the slave state without diff -r d71acfbd7319 -r 0e145bb05859 master/ioctl.c --- a/master/ioctl.c Thu Nov 06 08:55:35 2014 +0100 +++ b/master/ioctl.c Wed Nov 12 14:42:17 2014 +0100 @@ -1550,6 +1550,89 @@ /*****************************************************************************/ +/** Request EoE IP parameter setting. + * + * \return Zero on success, otherwise a negative error code. + */ +static ATTRIBUTES int ec_ioctl_slave_eoe_ip_param( + ec_master_t *master, /**< EtherCAT master. */ + void *arg /**< ioctl() argument. */ + ) +{ + ec_ioctl_slave_eoe_ip_t io; + ec_eoe_request_t req; + ec_slave_t *slave; + + if (copy_from_user(&io, (void __user *) arg, sizeof(io))) { + return -EFAULT; + } + + // init EoE request + ec_eoe_request_init(&req); + + req.mac_address_included = io.mac_address_included; + req.ip_address_included = io.ip_address_included; + req.subnet_mask_included = io.subnet_mask_included; + req.gateway_included = io.gateway_included; + req.dns_included = io.dns_included; + req.name_included = io.name_included; + + memcpy(req.mac_address, io.mac_address, ETH_ALEN); + req.ip_address = io.ip_address; + req.subnet_mask = io.subnet_mask; + req.gateway = io.gateway; + req.dns = io.dns; + memcpy(req.name, io.name, EC_MAX_HOSTNAME_SIZE); + + req.state = EC_INT_REQUEST_QUEUED; + + if (down_interruptible(&master->master_sem)) { + return -EINTR; + } + + if (!(slave = ec_master_find_slave( + master, 0, io.slave_position))) { + up(&master->master_sem); + EC_MASTER_ERR(master, "Slave %u does not exist!\n", + io.slave_position); + return -EINVAL; + } + + EC_MASTER_DBG(master, 1, "Scheduling EoE request.\n"); + + // schedule request. + list_add_tail(&req.list, &slave->eoe_requests); + + up(&master->master_sem); + + // wait for processing through FSM + if (wait_event_interruptible(master->request_queue, + req.state != EC_INT_REQUEST_QUEUED)) { + // interrupted by signal + down(&master->master_sem); + if (req.state == EC_INT_REQUEST_QUEUED) { + // abort request + list_del(&req.list); + up(&master->master_sem); + return -EINTR; + } + up(&master->master_sem); + } + + // wait until master FSM has finished processing + wait_event(master->request_queue, req.state != EC_INT_REQUEST_BUSY); + + io.result = req.result; + + if (copy_to_user((void __user *) arg, &io, sizeof(io))) { + return -EFAULT; + } + + return req.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO; +} + +/*****************************************************************************/ + /** Request the master from userspace. * * \return Zero on success, otherwise a negative error code. @@ -4205,6 +4288,13 @@ case EC_IOCTL_SLAVE_SOE_READ: ret = ec_ioctl_slave_soe_read(master, arg); break; + case EC_IOCTL_SLAVE_EOE_IP_PARAM: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_slave_eoe_ip_param(master, arg); + break; case EC_IOCTL_SLAVE_SOE_WRITE: if (!ctx->writable) { ret = -EPERM; diff -r d71acfbd7319 -r 0e145bb05859 master/ioctl.h --- a/master/ioctl.h Thu Nov 06 08:55:35 2014 +0100 +++ b/master/ioctl.h Wed Nov 12 14:42:17 2014 +0100 @@ -56,7 +56,7 @@ * * Increment this when changing the ioctl interface! */ -#define EC_IOCTL_VERSION_MAGIC 28 +#define EC_IOCTL_VERSION_MAGIC 29 // Command-line tool #define EC_IOCTL_MODULE EC_IOR(0x00, ec_ioctl_module_t) @@ -83,75 +83,76 @@ #define EC_IOCTL_SLAVE_FOE_WRITE EC_IOW(0x15, ec_ioctl_slave_foe_t) #define EC_IOCTL_SLAVE_SOE_READ EC_IOWR(0x16, ec_ioctl_slave_soe_read_t) #define EC_IOCTL_SLAVE_SOE_WRITE EC_IOWR(0x17, ec_ioctl_slave_soe_write_t) -#define EC_IOCTL_CONFIG EC_IOWR(0x18, ec_ioctl_config_t) -#define EC_IOCTL_CONFIG_PDO EC_IOWR(0x19, ec_ioctl_config_pdo_t) -#define EC_IOCTL_CONFIG_PDO_ENTRY EC_IOWR(0x1a, ec_ioctl_config_pdo_entry_t) -#define EC_IOCTL_CONFIG_SDO EC_IOWR(0x1b, ec_ioctl_config_sdo_t) -#define EC_IOCTL_CONFIG_IDN EC_IOWR(0x1c, ec_ioctl_config_idn_t) +#define EC_IOCTL_SLAVE_EOE_IP_PARAM EC_IOW(0x18, ec_ioctl_slave_eoe_ip_t) +#define EC_IOCTL_CONFIG EC_IOWR(0x19, ec_ioctl_config_t) +#define EC_IOCTL_CONFIG_PDO EC_IOWR(0x1a, ec_ioctl_config_pdo_t) +#define EC_IOCTL_CONFIG_PDO_ENTRY EC_IOWR(0x1b, ec_ioctl_config_pdo_entry_t) +#define EC_IOCTL_CONFIG_SDO EC_IOWR(0x1c, ec_ioctl_config_sdo_t) +#define EC_IOCTL_CONFIG_IDN EC_IOWR(0x1d, ec_ioctl_config_idn_t) #ifdef EC_EOE -#define EC_IOCTL_EOE_HANDLER EC_IOWR(0x1d, ec_ioctl_eoe_handler_t) +#define EC_IOCTL_EOE_HANDLER EC_IOWR(0x1e, ec_ioctl_eoe_handler_t) #endif // Application interface -#define EC_IOCTL_REQUEST EC_IO(0x1e) -#define EC_IOCTL_CREATE_DOMAIN EC_IO(0x1f) -#define EC_IOCTL_CREATE_SLAVE_CONFIG EC_IOWR(0x20, ec_ioctl_config_t) -#define EC_IOCTL_SELECT_REF_CLOCK EC_IOW(0x21, uint32_t) -#define EC_IOCTL_ACTIVATE EC_IOR(0x22, ec_ioctl_master_activate_t) -#define EC_IOCTL_DEACTIVATE EC_IO(0x23) -#define EC_IOCTL_SEND EC_IO(0x24) -#define EC_IOCTL_RECEIVE EC_IO(0x25) -#define EC_IOCTL_MASTER_STATE EC_IOR(0x26, ec_master_state_t) -#define EC_IOCTL_MASTER_LINK_STATE EC_IOWR(0x27, ec_ioctl_link_state_t) -#define EC_IOCTL_APP_TIME EC_IOW(0x28, ec_ioctl_app_time_t) -#define EC_IOCTL_SYNC_REF EC_IO(0x29) -#define EC_IOCTL_SYNC_SLAVES EC_IO(0x2a) -#define EC_IOCTL_REF_CLOCK_TIME EC_IOR(0x2b, uint32_t) -#define EC_IOCTL_SYNC_MON_QUEUE EC_IO(0x2c) -#define EC_IOCTL_SYNC_MON_PROCESS EC_IOR(0x2d, uint32_t) -#define EC_IOCTL_RESET EC_IO(0x2e) -#define EC_IOCTL_SC_SYNC EC_IOW(0x2f, ec_ioctl_config_t) -#define EC_IOCTL_SC_WATCHDOG EC_IOW(0x30, ec_ioctl_config_t) -#define EC_IOCTL_SC_ADD_PDO EC_IOW(0x31, ec_ioctl_config_pdo_t) -#define EC_IOCTL_SC_CLEAR_PDOS EC_IOW(0x32, ec_ioctl_config_pdo_t) -#define EC_IOCTL_SC_ADD_ENTRY EC_IOW(0x33, ec_ioctl_add_pdo_entry_t) -#define EC_IOCTL_SC_CLEAR_ENTRIES EC_IOW(0x34, ec_ioctl_config_pdo_t) -#define EC_IOCTL_SC_REG_PDO_ENTRY EC_IOWR(0x35, ec_ioctl_reg_pdo_entry_t) -#define EC_IOCTL_SC_REG_PDO_POS EC_IOWR(0x36, ec_ioctl_reg_pdo_pos_t) -#define EC_IOCTL_SC_DC EC_IOW(0x37, ec_ioctl_config_t) -#define EC_IOCTL_SC_SDO EC_IOW(0x38, ec_ioctl_sc_sdo_t) -#define EC_IOCTL_SC_EMERG_SIZE EC_IOW(0x39, ec_ioctl_sc_emerg_t) -#define EC_IOCTL_SC_EMERG_POP EC_IOWR(0x3a, ec_ioctl_sc_emerg_t) -#define EC_IOCTL_SC_EMERG_CLEAR EC_IOW(0x3b, ec_ioctl_sc_emerg_t) -#define EC_IOCTL_SC_EMERG_OVERRUNS EC_IOWR(0x3c, ec_ioctl_sc_emerg_t) -#define EC_IOCTL_SC_SDO_REQUEST EC_IOWR(0x3d, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SC_REG_REQUEST EC_IOWR(0x3e, ec_ioctl_reg_request_t) -#define EC_IOCTL_SC_VOE EC_IOWR(0x3f, ec_ioctl_voe_t) -#define EC_IOCTL_SC_STATE EC_IOWR(0x40, ec_ioctl_sc_state_t) -#define EC_IOCTL_SC_IDN EC_IOW(0x41, ec_ioctl_sc_idn_t) -#define EC_IOCTL_DOMAIN_SIZE EC_IO(0x42) -#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x43) -#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x44) -#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x45) -#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x46, ec_ioctl_domain_state_t) -#define EC_IOCTL_SDO_REQUEST_INDEX EC_IOWR(0x47, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x48, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x49, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x4a, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x4b, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x4c, ec_ioctl_sdo_request_t) -#define EC_IOCTL_REG_REQUEST_DATA EC_IOWR(0x4d, ec_ioctl_reg_request_t) -#define EC_IOCTL_REG_REQUEST_STATE EC_IOWR(0x4e, ec_ioctl_reg_request_t) -#define EC_IOCTL_REG_REQUEST_WRITE EC_IOWR(0x4f, ec_ioctl_reg_request_t) -#define EC_IOCTL_REG_REQUEST_READ EC_IOWR(0x50, ec_ioctl_reg_request_t) -#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x51, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x52, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_READ EC_IOW(0x53, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x54, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_WRITE EC_IOWR(0x55, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_EXEC EC_IOWR(0x56, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_DATA EC_IOWR(0x57, ec_ioctl_voe_t) -#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x58, size_t) +#define EC_IOCTL_REQUEST EC_IO(0x1f) +#define EC_IOCTL_CREATE_DOMAIN EC_IO(0x20) +#define EC_IOCTL_CREATE_SLAVE_CONFIG EC_IOWR(0x21, ec_ioctl_config_t) +#define EC_IOCTL_SELECT_REF_CLOCK EC_IOW(0x22, uint32_t) +#define EC_IOCTL_ACTIVATE EC_IOR(0x23, ec_ioctl_master_activate_t) +#define EC_IOCTL_DEACTIVATE EC_IO(0x24) +#define EC_IOCTL_SEND EC_IO(0x25) +#define EC_IOCTL_RECEIVE EC_IO(0x26) +#define EC_IOCTL_MASTER_STATE EC_IOR(0x27, ec_master_state_t) +#define EC_IOCTL_MASTER_LINK_STATE EC_IOWR(0x28, ec_ioctl_link_state_t) +#define EC_IOCTL_APP_TIME EC_IOW(0x29, ec_ioctl_app_time_t) +#define EC_IOCTL_SYNC_REF EC_IO(0x2a) +#define EC_IOCTL_SYNC_SLAVES EC_IO(0x2b) +#define EC_IOCTL_REF_CLOCK_TIME EC_IOR(0x2c, uint32_t) +#define EC_IOCTL_SYNC_MON_QUEUE EC_IO(0x2d) +#define EC_IOCTL_SYNC_MON_PROCESS EC_IOR(0x2e, uint32_t) +#define EC_IOCTL_RESET EC_IO(0x2f) +#define EC_IOCTL_SC_SYNC EC_IOW(0x30, ec_ioctl_config_t) +#define EC_IOCTL_SC_WATCHDOG EC_IOW(0x31, ec_ioctl_config_t) +#define EC_IOCTL_SC_ADD_PDO EC_IOW(0x32, ec_ioctl_config_pdo_t) +#define EC_IOCTL_SC_CLEAR_PDOS EC_IOW(0x33, ec_ioctl_config_pdo_t) +#define EC_IOCTL_SC_ADD_ENTRY EC_IOW(0x34, ec_ioctl_add_pdo_entry_t) +#define EC_IOCTL_SC_CLEAR_ENTRIES EC_IOW(0x35, ec_ioctl_config_pdo_t) +#define EC_IOCTL_SC_REG_PDO_ENTRY EC_IOWR(0x36, ec_ioctl_reg_pdo_entry_t) +#define EC_IOCTL_SC_REG_PDO_POS EC_IOWR(0x37, ec_ioctl_reg_pdo_pos_t) +#define EC_IOCTL_SC_DC EC_IOW(0x38, ec_ioctl_config_t) +#define EC_IOCTL_SC_SDO EC_IOW(0x39, ec_ioctl_sc_sdo_t) +#define EC_IOCTL_SC_EMERG_SIZE EC_IOW(0x3a, ec_ioctl_sc_emerg_t) +#define EC_IOCTL_SC_EMERG_POP EC_IOWR(0x3b, ec_ioctl_sc_emerg_t) +#define EC_IOCTL_SC_EMERG_CLEAR EC_IOW(0x3c, ec_ioctl_sc_emerg_t) +#define EC_IOCTL_SC_EMERG_OVERRUNS EC_IOWR(0x3d, ec_ioctl_sc_emerg_t) +#define EC_IOCTL_SC_SDO_REQUEST EC_IOWR(0x3e, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SC_REG_REQUEST EC_IOWR(0x3f, ec_ioctl_reg_request_t) +#define EC_IOCTL_SC_VOE EC_IOWR(0x40, ec_ioctl_voe_t) +#define EC_IOCTL_SC_STATE EC_IOWR(0x41, ec_ioctl_sc_state_t) +#define EC_IOCTL_SC_IDN EC_IOW(0x42, ec_ioctl_sc_idn_t) +#define EC_IOCTL_DOMAIN_SIZE EC_IO(0x43) +#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x44) +#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x45) +#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x46) +#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x47, ec_ioctl_domain_state_t) +#define EC_IOCTL_SDO_REQUEST_INDEX EC_IOWR(0x48, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x49, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x4a, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x4b, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x4c, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x4d, ec_ioctl_sdo_request_t) +#define EC_IOCTL_REG_REQUEST_DATA EC_IOWR(0x4e, ec_ioctl_reg_request_t) +#define EC_IOCTL_REG_REQUEST_STATE EC_IOWR(0x4f, ec_ioctl_reg_request_t) +#define EC_IOCTL_REG_REQUEST_WRITE EC_IOWR(0x50, ec_ioctl_reg_request_t) +#define EC_IOCTL_REG_REQUEST_READ EC_IOWR(0x51, ec_ioctl_reg_request_t) +#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x52, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x53, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_READ EC_IOW(0x54, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x55, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_WRITE EC_IOWR(0x56, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_EXEC EC_IOWR(0x57, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_DATA EC_IOWR(0x58, ec_ioctl_voe_t) +#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x59, size_t) /*****************************************************************************/ @@ -590,6 +591,37 @@ /*****************************************************************************/ +#define EC_ETH_ALEN 6 +#ifdef ETH_ALEN +#if ETH_ALEN != EC_ETH_ALEN +#error Ethernet address length mismatch +#endif +#endif + +typedef struct { + // input + uint16_t slave_position; + + uint8_t mac_address_included; + uint8_t ip_address_included; + uint8_t subnet_mask_included; + uint8_t gateway_included; + uint8_t dns_included; + uint8_t name_included; + + unsigned char mac_address[EC_ETH_ALEN]; + uint32_t ip_address; + uint32_t subnet_mask; + uint32_t gateway; + uint32_t dns; + char name[EC_MAX_HOSTNAME_SIZE]; + + // output + uint16_t result; +} ec_ioctl_slave_eoe_ip_t; + +/*****************************************************************************/ + typedef struct { // outputs void *process_data; diff -r d71acfbd7319 -r 0e145bb05859 master/slave.c --- a/master/slave.c Thu Nov 06 08:55:35 2014 +0100 +++ b/master/slave.c Wed Nov 12 14:42:17 2014 +0100 @@ -155,6 +155,7 @@ INIT_LIST_HEAD(&slave->reg_requests); INIT_LIST_HEAD(&slave->foe_requests); INIT_LIST_HEAD(&slave->soe_requests); + INIT_LIST_HEAD(&slave->eoe_requests); // create state machine object ec_fsm_slave_init(&slave->fsm, slave); @@ -211,6 +212,15 @@ request->state = EC_INT_REQUEST_FAILURE; } + while (!list_empty(&slave->eoe_requests)) { + ec_eoe_request_t *request = + list_entry(slave->eoe_requests.next, ec_eoe_request_t, list); + list_del_init(&request->list); // dequeue + EC_SLAVE_WARN(slave, "Discarding EoE request," + " slave about to be deleted.\n"); + request->state = EC_INT_REQUEST_FAILURE; + } + wake_up_all(&slave->master->request_queue); if (slave->config) { diff -r d71acfbd7319 -r 0e145bb05859 master/slave.h --- a/master/slave.h Thu Nov 06 08:55:35 2014 +0100 +++ b/master/slave.h Wed Nov 12 14:42:17 2014 +0100 @@ -228,8 +228,9 @@ struct list_head sdo_requests; /**< SDO access requests. */ struct list_head reg_requests; /**< Register access requests. */ - struct list_head foe_requests; /**< FoE write requests. */ - struct list_head soe_requests; /**< SoE write requests. */ + struct list_head foe_requests; /**< FoE requests. */ + struct list_head soe_requests; /**< SoE requests. */ + struct list_head eoe_requests; /**< EoE set IP parameter requests. */ ec_fsm_slave_t fsm; /**< Slave state machine. */ }; diff -r d71acfbd7319 -r 0e145bb05859 tool/CommandIp.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tool/CommandIp.cpp Wed Nov 12 14:42:17 2014 +0100 @@ -0,0 +1,258 @@ +/***************************************************************************** + * + * $Id$ + * + * Copyright (C) 2006-2014 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 + * + * --- + * + * The license mentioned above concerns the source code only. Using the + * EtherCAT technology and brand is only permitted in compliance with the + * industrial property and similar rights of Beckhoff Automation GmbH. + * + * vim: expandtab + * + ****************************************************************************/ + +#include +#include +#include + +#include +#include +using namespace std; + +#include "CommandIp.h" +#include "MasterDevice.h" + +/*****************************************************************************/ + +CommandIp::CommandIp(): + Command("ip", "Set EoE IP parameters.") +{ +} + +/*****************************************************************************/ + +string CommandIp::helpString(const string &binaryBaseName) const +{ + stringstream str; + + str << binaryBaseName << " " << getName() << " [OPTIONS] " << endl + << endl + << getBriefDescription() << endl + << endl + << "This command requires a single slave to be selected." << endl + << endl + << "IP parameters can be appended as argument pairs:" << endl + << endl + << " addr [/prefix] IP address (optionally with" << endl + << " decimal subnet prefix)" << endl + << " link Link-layer address (may contain" << endl + << " colons or hyphens)" << endl + << " default Default gateway" << endl + << " dns DNS server" << endl + << " name Host name (max. 32 byte)" << endl + << endl + << "IPv4 adresses can be given either in dot notation or as" << endl + << "hostnames, which will be automatically resolved." << endl + << endl + << "Command-specific options:" << endl + << " --alias -a " << endl + << " --position -p Slave selection. See the help of" << endl + << " the 'slaves' command." << endl + << endl + << numericInfo(); + + return str.str(); +} + +/****************************************************************************/ + +void CommandIp::execute(const StringVector &args) +{ + if (args.size() <= 0) { + return; + } + + if (args.size() % 2) { + stringstream err; + err << "'" << getName() << "' needs an even number of arguments!"; + throwInvalidUsageException(err); + } + + ec_ioctl_slave_eoe_ip_t io = {}; + + for (unsigned int argIdx = 0; argIdx < args.size(); argIdx += 2) { + string arg = args[argIdx]; + string val = args[argIdx + 1]; + std::transform(arg.begin(), arg.end(), arg.begin(), ::tolower); + + if (arg == "link") { + parseMac(io.mac_address, val); + io.mac_address_included = 1; + } + else if (arg == "addr") { + parseIpv4Prefix(&io, val); + io.ip_address_included = 1; + } + else if (arg == "default") { + resolveIpv4(&io.gateway, val); + io.gateway_included = 1; + } + else if (arg == "dns") { + resolveIpv4(&io.dns, val); + io.dns_included = 1; + } + else if (arg == "name") { + if (val.size() > EC_MAX_HOSTNAME_SIZE - 1) { + stringstream err; + err << "Name too long!"; + throwInvalidUsageException(err); + } + unsigned int i; + for (i = 0; i < val.size(); i++) { + io.name[i] = val[i]; + } + io.name[i] = 0; + io.name_included = 1; + } + else { + stringstream err; + err << "Unknown argument '" << args[argIdx] << "'!"; + throwInvalidUsageException(err); + } + } + + MasterDevice m(getSingleMasterIndex()); + m.open(MasterDevice::ReadWrite); + SlaveList slaves = selectedSlaves(m); + if (slaves.size() != 1) { + throwSingleSlaveRequired(slaves.size()); + } + io.slave_position = slaves.front().position; + + // execute actual request + try { + m.setIpParam(&io); + } catch (MasterDeviceException &e) { + throw e; + } +} + +/*****************************************************************************/ + +void CommandIp::parseMac(unsigned char mac[EC_ETH_ALEN], const string &str) +{ + unsigned int pos = 0; + + for (unsigned int i = 0; i < EC_ETH_ALEN; i++) { + if (pos + 2 > str.size()) { + stringstream err; + err << "Incomplete MAC address!"; + throwInvalidUsageException(err); + } + + string byteStr = str.substr(pos, 2); + pos += 2; + + stringstream s; + s << byteStr; + unsigned int byteValue; + s >> hex >> byteValue; + if (s.fail() || !s.eof() || byteValue > 0xff) { + stringstream err; + err << "Invalid MAC address!"; + throwInvalidUsageException(err); + } + mac[i] = byteValue; + + while (pos < str.size() && (str[pos] == ':' || str[pos] == '-')) { + pos++; + } + } +} + +/*****************************************************************************/ + +void CommandIp::parseIpv4Prefix(ec_ioctl_slave_eoe_ip_t *io, + const string &str) +{ + size_t pos = str.find('/'); + string host; + + io->subnet_mask_included = pos != string::npos; + + if (pos == string::npos) { // no prefix found + host = str; + } + else { + host = str.substr(0, pos); + string prefixStr = str.substr(pos + 1, string::npos); + stringstream s; + s << prefixStr; + unsigned int prefix; + s >> prefix; + if (s.fail() || !s.eof() || prefix > 32) { + stringstream err; + err << "Invalid prefix '" << prefixStr << "'!"; + throwInvalidUsageException(err); + } + uint32_t mask = 0; + for (unsigned int bit = 0; bit < prefix; bit++) { + mask |= (1 << (31 - bit)); + } + io->subnet_mask = htonl(mask); + } + + resolveIpv4(&io->ip_address, host); +} + +/*****************************************************************************/ + +void CommandIp::resolveIpv4(uint32_t *addr, const string &str) +{ + struct addrinfo hints = {}; + struct addrinfo *res; + + hints.ai_family = AF_INET; // only IPv4 + + int ret = getaddrinfo(str.c_str(), NULL, &hints, &res); + if (ret) { + stringstream err; + err << "Lookup of '" << str << "' failed: " + << gai_strerror(ret) << endl; + throwCommandException(err.str()); + } + + if (!res) { // returned list is empty + stringstream err; + err << "Lookup of '" << str << "' failed." << endl; + throwCommandException(err.str()); + } + + sockaddr_in *sin = (sockaddr_in *) res->ai_addr; + for (unsigned int i = 0; i < 4; i++) { + ((unsigned char *) addr)[i] = + ((unsigned char *) &sin->sin_addr.s_addr)[i]; + } + + freeaddrinfo(res); +} + +/****************************************************************************/ diff -r d71acfbd7319 -r 0e145bb05859 tool/CommandIp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tool/CommandIp.h Wed Nov 12 14:42:17 2014 +0100 @@ -0,0 +1,55 @@ +/***************************************************************************** + * + * $Id$ + * + * Copyright (C) 2006-2014 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 + * + * --- + * + * The license mentioned above concerns the source code only. Using the + * EtherCAT technology and brand is only permitted in compliance with the + * industrial property and similar rights of Beckhoff Automation GmbH. + * + ****************************************************************************/ + +#ifndef __COMMANDIP_H__ +#define __COMMANDIP_H__ + +#include "Command.h" + +/****************************************************************************/ + +class CommandIp: + public Command +{ + public: + CommandIp(); + + string helpString(const string &) const; + void execute(const StringVector &); + + protected: + static void parseMac(unsigned char [6], const string &); + static void parseIpv4Prefix(ec_ioctl_slave_eoe_ip_t *, + const string &); + static void resolveIpv4(uint32_t *, const string &); +}; + +/****************************************************************************/ + +#endif diff -r d71acfbd7319 -r 0e145bb05859 tool/Makefile.am --- a/tool/Makefile.am Thu Nov 06 08:55:35 2014 +0100 +++ b/tool/Makefile.am Wed Nov 12 14:42:17 2014 +0100 @@ -48,6 +48,7 @@ CommandFoeRead.cpp \ CommandFoeWrite.cpp \ CommandGraph.cpp \ + CommandIp.cpp \ CommandMaster.cpp \ CommandPdos.cpp \ CommandRegRead.cpp \ @@ -90,6 +91,7 @@ CommandFoeRead.h \ CommandFoeWrite.h \ CommandGraph.h \ + CommandIp.h \ CommandMaster.h \ CommandPdos.h \ CommandRegRead.h \ diff -r d71acfbd7319 -r 0e145bb05859 tool/MasterDevice.cpp --- a/tool/MasterDevice.cpp Thu Nov 06 08:55:35 2014 +0100 +++ b/tool/MasterDevice.cpp Wed Nov 12 14:42:17 2014 +0100 @@ -585,4 +585,19 @@ } } +/****************************************************************************/ + +void MasterDevice::setIpParam(ec_ioctl_slave_eoe_ip_t *data) +{ + if (ioctl(fd, EC_IOCTL_SLAVE_EOE_IP_PARAM, data) < 0) { + if (errno == EIO && data->result) { + throw MasterDeviceEoeException(data->result); + } else { + stringstream err; + err << "Failed to set IP parameters: " << strerror(errno); + throw MasterDeviceException(err); + } + } +} + /*****************************************************************************/ diff -r d71acfbd7319 -r 0e145bb05859 tool/MasterDevice.h --- a/tool/MasterDevice.h Thu Nov 06 08:55:35 2014 +0100 +++ b/tool/MasterDevice.h Wed Nov 12 14:42:17 2014 +0100 @@ -94,6 +94,23 @@ /****************************************************************************/ +class MasterDeviceEoeException: + public MasterDeviceException +{ + friend class MasterDevice; + + public: + uint16_t result; + + protected: + /** Constructor with error code parameter. */ + MasterDeviceEoeException(uint16_t result): + MasterDeviceException("EoE set IP parameter failed."), + result(result) {}; +}; + +/****************************************************************************/ + class MasterDevice { public: @@ -144,6 +161,7 @@ #endif void readSoe(ec_ioctl_slave_soe_read_t *); void writeSoe(ec_ioctl_slave_soe_write_t *); + void setIpParam(ec_ioctl_slave_eoe_ip_t *); unsigned int getMasterCount() const {return masterCount;} diff -r d71acfbd7319 -r 0e145bb05859 tool/main.cpp --- a/tool/main.cpp Thu Nov 06 08:55:35 2014 +0100 +++ b/tool/main.cpp Wed Nov 12 14:42:17 2014 +0100 @@ -48,6 +48,7 @@ #include "CommandFoeRead.h" #include "CommandFoeWrite.h" #include "CommandGraph.h" +#include "CommandIp.h" #include "CommandMaster.h" #include "CommandPdos.h" #include "CommandRegRead.h" @@ -288,6 +289,7 @@ commandList.push_back(new CommandFoeRead()); commandList.push_back(new CommandFoeWrite()); commandList.push_back(new CommandGraph()); + commandList.push_back(new CommandIp()); commandList.push_back(new CommandMaster()); commandList.push_back(new CommandPdos()); commandList.push_back(new CommandRegRead());