diff --git a/documentation/Makefile b/documentation/Makefile index ae5cadcb..92ee548e 100644 --- a/documentation/Makefile +++ b/documentation/Makefile @@ -21,6 +21,7 @@ COMMANDS := \ foe_read \ foe_write \ graph \ + ip \ master \ pdos \ reg_read \ diff --git a/documentation/ethercat_doc.tex b/documentation/ethercat_doc.tex index 51205863..8e90fb5e 100644 --- a/documentation/ethercat_doc.tex +++ b/documentation/ethercat_doc.tex @@ -2058,6 +2058,9 @@ index and Y is the decimal alias address. \end{description} +For some hints on how to configure these virtual interfaces, see +\autoref{sec:eoe-config}. + Frames sent to these interfaces are forwarded to the associated slaves by the master. Frames, that are received by the slaves, are fetched by the master and forwarded to the virtual interfaces. @@ -2183,11 +2186,54 @@ is executed each timer interrupt. This guarantees a constant bandwidth, but poses the new problem of concurrent access to the master. The locking mechanisms needed for this are introduced in \autoref{sec:concurr}. -\paragraph{Automatic Configuration} +\subsection{EoE Interface Configuration} +\label{sec:eoe-config} -By default, slaves are left in PREOP state, if no configuration is applied. If -an EoE interface link is set to ``up'', the requested slave's -application-layer state is automatically set to OP. +The configuration of the EoE network interfaces is a matter of using standard +Linux networking infrastructure commands like \lstinline+ifconfig+, +\lstinline+ip+ and \lstinline+brctl+. Though this lies not in the scope of +this document, some hints and examples are provided in this section. + +In the below examples it is assumed, that there are two slaves (0 and 1) with +EoE support in the bus. The first decision to make is whether to use a bridged +or routed environment. + +\paragraph{Bridging} A common solution is to create a bridge containing all EoE +interfaces: + +\begin{lstlisting} +$ `\textbf{brctl addbr br0}` +$ `\textbf{ip addr add 192.168.100.1/24 dev br0}` +$ `\textbf{brctl addif br0 eoe0s0}` +$ `\textbf{brctl addif br0 eoe0s1}` +\end{lstlisting} + +The above example allows to access IPv4 nodes using subnet 192.168.100.0/24 +connected to the EtherCAT bus via EoE. Please note, that the example only +contains ad-hoc configuration commands: If the bus topology changes, the EoE +interfaces are re-created and have to be added to the bridge again. Therefore +it is highly recommended to use the networking configuration infrastructure of +the used Linux distribution to store this configuration permanently, so that +appearing EoE devices are added automatically. + +\paragraph{Routing} Another possibility is to create an IP subnet for each EoE +interface: + +\begin{lstlisting} +$ `\textbf{ip addr add 192.168.200.1/24 dev eoe0s0}` +$ `\textbf{ip addr add 192.168.201.1/24 dev eoe0s1}` +$ `\textbf{echo 1 > /proc/sys/net/ipv4/ip\_forward}` +\end{lstlisting} + +This example is again only an ad-hoc configuration (see above). Please note, +that it is necessary to set the default gateways properly on the IP nodes +connected to the EoE slaves, if they shall be able to communicate between the +different EoE interfaces / IP networks. + +\paragraph{Setting IP Parameters} If IP address and other parameters of the +EoE remote nodes (not the EoE interfaces on the master side) have to be set, +this can be achieved via the \lstinline+ethercat ip+ command-line tool (see +\autoref{sec:ipparam}). %------------------------------------------------------------------------------ @@ -2444,6 +2490,28 @@ created, if the \lstinline+udev+ Package is installed. See %------------------------------------------------------------------------------ +\subsection{Setting Ethernet-over-EtherCAT IP Parameters} +\label{sec:ipparam} + +Slaves can have own IP stack implementations accessible via EoE. Since some of +them do not provide other mechanisms to set IP parameters (because they only +have an EtherCAT interface), there is a possibility to set the below +parameters via EoE: + +\begin{itemize} +\item Ethernet MAC address\footnote{The MAC address of the virtual EoE remote +interface, not the one of the EtherCAT interface.}, +\item IPv4 address, +\item IPv4 subnet mask, +\item IPv4 default gateway, +\item IPv4 DNS server, +\item DNS host name. +\end{itemize} + +\lstinputlisting[basicstyle=\ttfamily\footnotesize]{external/ethercat_ip} + +%------------------------------------------------------------------------------ + \subsection{Master and Ethernet Devices} \lstinputlisting[basicstyle=\ttfamily\footnotesize]{external/ethercat_master} diff --git a/master/Kbuild.in b/master/Kbuild.in index bfb5da3f..393e68d5 100644 --- a/master/Kbuild.in +++ b/master/Kbuild.in @@ -69,7 +69,7 @@ ec_master-objs := \ voe_handler.o ifeq (@ENABLE_EOE@,1) -ec_master-objs += ethernet.o +ec_master-objs += eoe_request.o ethernet.o fsm_eoe.o endif ifeq (@ENABLE_DEBUG_IF@,1) diff --git a/master/Makefile.am b/master/Makefile.am index f1b90aa3..c1f768ef 100644 --- a/master/Makefile.am +++ b/master/Makefile.am @@ -31,6 +31,7 @@ noinst_HEADERS = \ device.c device.h \ domain.c domain.h \ doxygen.c \ + eoe_request.c eoe_request.h \ ethernet.c ethernet.h \ flag.c flag.h \ fmmu_config.c fmmu_config.h \ @@ -38,6 +39,7 @@ noinst_HEADERS = \ 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 --git a/master/eoe_request.c b/master/eoe_request.c new file mode 100644 index 00000000..90b96233 --- /dev/null +++ b/master/eoe_request.c @@ -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 --git a/master/eoe_request.h b/master/eoe_request.h new file mode 100644 index 00000000..85c7d193 --- /dev/null +++ b/master/eoe_request.h @@ -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 --git a/master/ethernet.c b/master/ethernet.c index 15d79b6a..dc519733 100644 --- a/master/ethernet.c +++ b/master/ethernet.c @@ -307,7 +307,7 @@ int ec_eoe_send(ec_eoe_t *eoe /**< EoE handler */) if (IS_ERR(data)) return PTR_ERR(data); - EC_WRITE_U8 (data, 0x00); // eoe fragment req. + EC_WRITE_U8 (data, EC_EOE_FRAMETYPE_INIT_REQ); // Initiate EoE Request EC_WRITE_U8 (data + 1, last_fragment); EC_WRITE_U16(data + 2, ((eoe->tx_fragment_number & 0x3F) | (complete_offset & 0x3F) << 6 | @@ -494,7 +494,7 @@ void ec_eoe_state_rx_fetch(ec_eoe_t *eoe /**< EoE handler */) frame_type = EC_READ_U16(data) & 0x000F; - if (frame_type != 0x00) { + if (frame_type != EC_EOE_FRAMETYPE_INIT_REQ) { // EoE Fragment Data #if EOE_DEBUG_LEVEL >= 1 EC_SLAVE_WARN(eoe->slave, "%s: Other frame received." " Dropping.\n", eoe->dev->name); diff --git a/master/ethernet.h b/master/ethernet.h index 95f6a00a..ef0a8810 100644 --- a/master/ethernet.h +++ b/master/ethernet.h @@ -38,6 +38,18 @@ /****************************************************************************/ +/** EoE frame types. + */ +enum { + EC_EOE_FRAMETYPE_INIT_REQ = 0x00, /** Initiate EoE Request. */ + EC_EOE_FRAMETYPE_SET_IP_REQ = 0x02, /** Set IP Parameter Request. */ + EC_EOE_FRAMETYPE_SET_IP_RES = 0x03, /** Set IP Parameter Response. */ + EC_EOE_FRAMETYPE_FILT_REQ = 0x04, /** Set Address Filter Request. */ + EC_EOE_FRAMETYPE_FILT_RES = 0x05, /** Set Address Filter Response. */ +}; + +/*****************************************************************************/ + /** Queued frame structure. */ diff --git a/master/fsm_eoe.c b/master/fsm_eoe.c new file mode 100644 index 00000000..5c83f57e --- /dev/null +++ b/master/fsm_eoe.c @@ -0,0 +1,482 @@ +/****************************************************************************** + * + * $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; + + // Note: based on wireshark packet filter it suggests that the EOE_INIT + // information is a fixed size with fixed information positions. + // see: packet-ecatmb.h and packet-ecatmb.c + // However, TwinCAT 2.1 testing also indicates that if a piece of + // information is missing then all subsequent items are ignored + // Also, if you want DHCP, then only set the mac address. + size_t size = 8 + // header + flags + ETH_ALEN + // mac address + 4 + // ip address + 4 + // subnet mask + 4 + // gateway + 4 + // dns server + EC_MAX_HOSTNAME_SIZE; // dns name + + data = ec_slave_mbox_prepare_send(slave, datagram, EC_MBOX_TYPE_EOE, + size); + if (IS_ERR(data)) { + return PTR_ERR(data); + } + + // zero data + memset(data, 0, size); + + // header + EC_WRITE_U8(data, EC_EOE_FRAMETYPE_SET_IP_REQ); // Set IP parameter req. + EC_WRITE_U8(data + 1, 0x00); // not used + EC_WRITE_U16(data + 2, 0x0000); // not used + + 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) { + uint32_t swapped = htonl(req->ip_address); + memcpy(cur, &swapped, 4); + } + cur += 4; + + if (req->subnet_mask_included) { + uint32_t swapped = htonl(req->subnet_mask); + memcpy(cur, &swapped, 4); + } + cur += 4; + + if (req->gateway_included) { + uint32_t swapped = htonl(req->gateway); + memcpy(cur, &swapped, 4); + } + cur += 4; + + if (req->dns_included) { + uint32_t swapped = htonl(req->dns); + memcpy(cur, &swapped, 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 --git a/master/fsm_eoe.h b/master/fsm_eoe.h new file mode 100644 index 00000000..949b0798 --- /dev/null +++ b/master/fsm_eoe.h @@ -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 --git a/master/fsm_foe.c b/master/fsm_foe.c index ccb03e50..378ae369 100644 --- a/master/fsm_foe.c +++ b/master/fsm_foe.c @@ -58,7 +58,7 @@ enum { EC_FOE_OPCODE_ACK = 4, /**< Acknowledge. */ EC_FOE_OPCODE_ERR = 5, /**< Error. */ EC_FOE_OPCODE_BUSY = 6 /**< Busy. */ -} ec_foe_opcode_t; +}; /****************************************************************************/ diff --git a/master/fsm_slave.c b/master/fsm_slave.c index 3728e33d..6e1f9c36 100644 --- a/master/fsm_slave.c +++ b/master/fsm_slave.c @@ -44,6 +44,10 @@ int ec_fsm_slave_action_process_foe(ec_fsm_slave_t *, ec_datagram_t *); 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 *); +#ifdef EC_EOE +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 *); +#endif /****************************************************************************/ @@ -63,11 +67,17 @@ void ec_fsm_slave_init( fsm->reg_request = NULL; fsm->foe_request = NULL; fsm->soe_request = NULL; +#ifdef EC_EOE + fsm->eoe_request = NULL; +#endif // 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); +#ifdef EC_EOE + ec_fsm_eoe_init(&fsm->fsm_eoe); +#endif } /****************************************************************************/ @@ -100,10 +110,20 @@ void ec_fsm_slave_clear( wake_up_all(&fsm->slave->master->request_queue); } +#ifdef EC_EOE + if (fsm->eoe_request) { + fsm->soe_request->state = EC_INT_REQUEST_FAILURE; + wake_up_all(&fsm->slave->master->request_queue); + } +#endif + // 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); +#ifdef EC_EOE + ec_fsm_eoe_clear(&fsm->fsm_eoe); +#endif } /****************************************************************************/ @@ -202,6 +222,13 @@ void ec_fsm_slave_state_ready( if (ec_fsm_slave_action_process_soe(fsm, datagram)) { return; } + +#ifdef EC_EOE + // Check for pending EoE IP parameter requests + if (ec_fsm_slave_action_process_eoe(fsm, datagram)) { + return; + } +#endif } /****************************************************************************/ @@ -232,7 +259,7 @@ int ec_fsm_slave_action_process_sdo( 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) { @@ -240,7 +267,7 @@ int ec_fsm_slave_action_process_sdo( 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; @@ -334,7 +361,7 @@ int ec_fsm_slave_action_process_reg( 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! @@ -436,7 +463,7 @@ int ec_fsm_slave_action_process_foe( 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; @@ -513,7 +540,7 @@ int ec_fsm_slave_action_process_soe( 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) { @@ -572,3 +599,87 @@ void ec_fsm_slave_state_soe_request( } /****************************************************************************/ + +#ifdef EC_EOE +/** 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; +} + +/****************************************************************************/ +#endif diff --git a/master/fsm_slave.h b/master/fsm_slave.h index 55685da5..079bd5f8 100644 --- a/master/fsm_slave.h +++ b/master/fsm_slave.h @@ -33,9 +33,15 @@ #include "datagram.h" #include "sdo_request.h" #include "reg_request.h" +#ifdef EC_EOE +#include "eoe_request.h" +#endif #include "fsm_coe.h" #include "fsm_foe.h" #include "fsm_soe.h" +#ifdef EC_EOE +#include "fsm_eoe.h" +#endif /****************************************************************************/ @@ -54,10 +60,16 @@ struct ec_fsm_slave { 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. */ +#ifdef EC_EOE + ec_eoe_request_t *eoe_request; /**< SoE request to process. */ +#endif 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. */ +#ifdef EC_EOE + ec_fsm_eoe_t fsm_eoe; /**< EoE state machine. */ +#endif }; /****************************************************************************/ diff --git a/master/fsm_soe.c b/master/fsm_soe.c index 7a11cfdd..161e3e3d 100644 --- a/master/fsm_soe.c +++ b/master/fsm_soe.c @@ -35,7 +35,7 @@ /** SoE operations */ -enum ec_soe_opcodes { +enum { OPCODE_READ_REQUEST = 0x01, /**< Read request. */ OPCODE_READ_RESPONSE = 0x02, /**< Read response. */ OPCODE_WRITE_REQUEST = 0x03, /**< Write request. */ diff --git a/master/globals.h b/master/globals.h index b540360e..da738e8b 100644 --- a/master/globals.h +++ b/master/globals.h @@ -103,6 +103,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 @@ -130,6 +136,9 @@ typedef enum { } ec_slave_state_t; /** Supported mailbox protocols. + * + * Not to mix up with the mailbox type field in the mailbox header defined in + * master/mailbox.h. */ enum { EC_MBOX_AOE = 0x01, /**< ADS over EtherCAT */ diff --git a/master/ioctl.c b/master/ioctl.c index 8d577d29..042e9d2a 100644 --- a/master/ioctl.c +++ b/master/ioctl.c @@ -1622,6 +1622,91 @@ static ATTRIBUTES int ec_ioctl_eoe_handler( /****************************************************************************/ +#ifdef EC_EOE +/** 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; +} +#endif + +/*****************************************************************************/ + /** Request the master from userspace. * * \return Zero on success, otherwise a negative error code. @@ -4686,6 +4771,15 @@ long EC_IOCTL( case EC_IOCTL_SLAVE_SOE_READ: ret = ec_ioctl_slave_soe_read(master, arg); break; +#ifdef EC_EOE + case EC_IOCTL_SLAVE_EOE_IP_PARAM: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_slave_eoe_ip_param(master, arg); + break; +#endif case EC_IOCTL_SLAVE_SOE_WRITE: if (!ctx->writable) { ret = -EPERM; diff --git a/master/ioctl.h b/master/ioctl.h index d18e37c7..61c8354f 100644 --- a/master/ioctl.h +++ b/master/ioctl.h @@ -47,7 +47,7 @@ * * Increment this when changing the ioctl interface! */ -#define EC_IOCTL_VERSION_MAGIC 34 +#define EC_IOCTL_VERSION_MAGIC 35 // Command-line tool #define EC_IOCTL_MODULE EC_IOR(0x00, ec_ioctl_module_t) @@ -74,85 +74,88 @@ #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_CONFIG_FLAG EC_IOWR(0x1d, ec_ioctl_config_flag_t) #ifdef EC_EOE -#define EC_IOCTL_EOE_HANDLER EC_IOWR(0x1e, ec_ioctl_eoe_handler_t) +#define EC_IOCTL_SLAVE_EOE_IP_PARAM EC_IOW(0x18, ec_ioctl_slave_eoe_ip_t) +#endif +#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) +#define EC_IOCTL_CONFIG_FLAG EC_IOWR(0x1e, ec_ioctl_config_flag_t) +#ifdef EC_EOE +#define EC_IOCTL_EOE_HANDLER EC_IOWR(0x1f, ec_ioctl_eoe_handler_t) #endif // Application interface -#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, uint64_t) -#define EC_IOCTL_SYNC_REF EC_IO(0x2a) -#define EC_IOCTL_SYNC_REF_TO EC_IOW(0x2b, uint64_t) -#define EC_IOCTL_SYNC_SLAVES EC_IO(0x2c) -#define EC_IOCTL_REF_CLOCK_TIME EC_IOR(0x2d, uint32_t) -#define EC_IOCTL_SYNC_MON_QUEUE EC_IO(0x2e) -#define EC_IOCTL_SYNC_MON_PROCESS EC_IOR(0x2f, uint32_t) -#define EC_IOCTL_RESET EC_IO(0x30) -#define EC_IOCTL_SC_SYNC EC_IOW(0x31, ec_ioctl_config_t) -#define EC_IOCTL_SC_WATCHDOG EC_IOW(0x32, ec_ioctl_config_t) -#define EC_IOCTL_SC_ADD_PDO EC_IOW(0x33, ec_ioctl_config_pdo_t) -#define EC_IOCTL_SC_CLEAR_PDOS EC_IOW(0x34, ec_ioctl_config_pdo_t) -#define EC_IOCTL_SC_ADD_ENTRY EC_IOW(0x35, ec_ioctl_add_pdo_entry_t) -#define EC_IOCTL_SC_CLEAR_ENTRIES EC_IOW(0x36, ec_ioctl_config_pdo_t) -#define EC_IOCTL_SC_REG_PDO_ENTRY EC_IOWR(0x37, ec_ioctl_reg_pdo_entry_t) -#define EC_IOCTL_SC_REG_PDO_POS EC_IOWR(0x38, ec_ioctl_reg_pdo_pos_t) -#define EC_IOCTL_SC_DC EC_IOW(0x39, ec_ioctl_config_t) -#define EC_IOCTL_SC_SDO EC_IOW(0x3a, ec_ioctl_sc_sdo_t) -#define EC_IOCTL_SC_EMERG_SIZE EC_IOW(0x3b, ec_ioctl_sc_emerg_t) -#define EC_IOCTL_SC_EMERG_POP EC_IOWR(0x3c, ec_ioctl_sc_emerg_t) -#define EC_IOCTL_SC_EMERG_CLEAR EC_IOW(0x3d, ec_ioctl_sc_emerg_t) -#define EC_IOCTL_SC_EMERG_OVERRUNS EC_IOWR(0x3e, ec_ioctl_sc_emerg_t) -#define EC_IOCTL_SC_SDO_REQUEST EC_IOWR(0x3f, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SC_SOE_REQUEST EC_IOWR(0x40, ec_ioctl_soe_request_t) -#define EC_IOCTL_SC_REG_REQUEST EC_IOWR(0x41, ec_ioctl_reg_request_t) -#define EC_IOCTL_SC_VOE EC_IOWR(0x42, ec_ioctl_voe_t) -#define EC_IOCTL_SC_STATE EC_IOWR(0x43, ec_ioctl_sc_state_t) -#define EC_IOCTL_SC_IDN EC_IOW(0x44, ec_ioctl_sc_idn_t) -#define EC_IOCTL_SC_FLAG EC_IOW(0x45, ec_ioctl_sc_flag_t) -#define EC_IOCTL_DOMAIN_SIZE EC_IO(0x46) -#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x47) -#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x48) -#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x49) -#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x4a, ec_ioctl_domain_state_t) -#define EC_IOCTL_SDO_REQUEST_INDEX EC_IOWR(0x4b, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x4c, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x4d, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x4e, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x4f, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x50, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SOE_REQUEST_IDN EC_IOWR(0x51, ec_ioctl_soe_request_t) -#define EC_IOCTL_SOE_REQUEST_TIMEOUT EC_IOWR(0x52, ec_ioctl_soe_request_t) -#define EC_IOCTL_SOE_REQUEST_STATE EC_IOWR(0x53, ec_ioctl_soe_request_t) -#define EC_IOCTL_SOE_REQUEST_READ EC_IOWR(0x54, ec_ioctl_soe_request_t) -#define EC_IOCTL_SOE_REQUEST_WRITE EC_IOWR(0x55, ec_ioctl_soe_request_t) -#define EC_IOCTL_SOE_REQUEST_DATA EC_IOWR(0x56, ec_ioctl_soe_request_t) -#define EC_IOCTL_REG_REQUEST_DATA EC_IOWR(0x57, ec_ioctl_reg_request_t) -#define EC_IOCTL_REG_REQUEST_STATE EC_IOWR(0x58, ec_ioctl_reg_request_t) -#define EC_IOCTL_REG_REQUEST_WRITE EC_IOWR(0x59, ec_ioctl_reg_request_t) -#define EC_IOCTL_REG_REQUEST_READ EC_IOWR(0x5a, ec_ioctl_reg_request_t) -#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x5b, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x5c, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_READ EC_IOW(0x5d, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x5e, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_WRITE EC_IOWR(0x5f, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_EXEC EC_IOWR(0x60, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_DATA EC_IOWR(0x61, ec_ioctl_voe_t) -#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x62, size_t) +#define EC_IOCTL_REQUEST EC_IO(0x20) +#define EC_IOCTL_CREATE_DOMAIN EC_IO(0x21) +#define EC_IOCTL_CREATE_SLAVE_CONFIG EC_IOWR(0x22, ec_ioctl_config_t) +#define EC_IOCTL_SELECT_REF_CLOCK EC_IOW(0x23, uint32_t) +#define EC_IOCTL_ACTIVATE EC_IOR(0x24, ec_ioctl_master_activate_t) +#define EC_IOCTL_DEACTIVATE EC_IO(0x25) +#define EC_IOCTL_SEND EC_IO(0x26) +#define EC_IOCTL_RECEIVE EC_IO(0x27) +#define EC_IOCTL_MASTER_STATE EC_IOR(0x28, ec_master_state_t) +#define EC_IOCTL_MASTER_LINK_STATE EC_IOWR(0x29, ec_ioctl_link_state_t) +#define EC_IOCTL_APP_TIME EC_IOW(0x2a, uint64_t) +#define EC_IOCTL_SYNC_REF EC_IO(0x2b) +#define EC_IOCTL_SYNC_REF_TO EC_IOW(0x2c, uint64_t) +#define EC_IOCTL_SYNC_SLAVES EC_IO(0x2d) +#define EC_IOCTL_REF_CLOCK_TIME EC_IOR(0x2e, uint32_t) +#define EC_IOCTL_SYNC_MON_QUEUE EC_IO(0x2f) +#define EC_IOCTL_SYNC_MON_PROCESS EC_IOR(0x30, uint32_t) +#define EC_IOCTL_RESET EC_IO(0x31) +#define EC_IOCTL_SC_SYNC EC_IOW(0x32, ec_ioctl_config_t) +#define EC_IOCTL_SC_WATCHDOG EC_IOW(0x33, ec_ioctl_config_t) +#define EC_IOCTL_SC_ADD_PDO EC_IOW(0x34, ec_ioctl_config_pdo_t) +#define EC_IOCTL_SC_CLEAR_PDOS EC_IOW(0x35, ec_ioctl_config_pdo_t) +#define EC_IOCTL_SC_ADD_ENTRY EC_IOW(0x36, ec_ioctl_add_pdo_entry_t) +#define EC_IOCTL_SC_CLEAR_ENTRIES EC_IOW(0x37, ec_ioctl_config_pdo_t) +#define EC_IOCTL_SC_REG_PDO_ENTRY EC_IOWR(0x38, ec_ioctl_reg_pdo_entry_t) +#define EC_IOCTL_SC_REG_PDO_POS EC_IOWR(0x39, ec_ioctl_reg_pdo_pos_t) +#define EC_IOCTL_SC_DC EC_IOW(0x3a, ec_ioctl_config_t) +#define EC_IOCTL_SC_SDO EC_IOW(0x3b, ec_ioctl_sc_sdo_t) +#define EC_IOCTL_SC_EMERG_SIZE EC_IOW(0x3c, ec_ioctl_sc_emerg_t) +#define EC_IOCTL_SC_EMERG_POP EC_IOWR(0x3d, ec_ioctl_sc_emerg_t) +#define EC_IOCTL_SC_EMERG_CLEAR EC_IOW(0x3e, ec_ioctl_sc_emerg_t) +#define EC_IOCTL_SC_EMERG_OVERRUNS EC_IOWR(0x3f, ec_ioctl_sc_emerg_t) +#define EC_IOCTL_SC_SDO_REQUEST EC_IOWR(0x40, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SC_SOE_REQUEST EC_IOWR(0x41, ec_ioctl_soe_request_t) +#define EC_IOCTL_SC_REG_REQUEST EC_IOWR(0x42, ec_ioctl_reg_request_t) +#define EC_IOCTL_SC_VOE EC_IOWR(0x43, ec_ioctl_voe_t) +#define EC_IOCTL_SC_STATE EC_IOWR(0x44, ec_ioctl_sc_state_t) +#define EC_IOCTL_SC_IDN EC_IOW(0x45, ec_ioctl_sc_idn_t) +#define EC_IOCTL_SC_FLAG EC_IOW(0x46, ec_ioctl_sc_flag_t) +#define EC_IOCTL_DOMAIN_SIZE EC_IO(0x47) +#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x48) +#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x49) +#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x4a) +#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x4b, ec_ioctl_domain_state_t) +#define EC_IOCTL_SDO_REQUEST_INDEX EC_IOWR(0x4c, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x4d, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x4e, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x4f, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x50, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x51, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SOE_REQUEST_IDN EC_IOWR(0x52, ec_ioctl_soe_request_t) +#define EC_IOCTL_SOE_REQUEST_TIMEOUT EC_IOWR(0x53, ec_ioctl_soe_request_t) +#define EC_IOCTL_SOE_REQUEST_STATE EC_IOWR(0x54, ec_ioctl_soe_request_t) +#define EC_IOCTL_SOE_REQUEST_READ EC_IOWR(0x55, ec_ioctl_soe_request_t) +#define EC_IOCTL_SOE_REQUEST_WRITE EC_IOWR(0x56, ec_ioctl_soe_request_t) +#define EC_IOCTL_SOE_REQUEST_DATA EC_IOWR(0x57, ec_ioctl_soe_request_t) +#define EC_IOCTL_REG_REQUEST_DATA EC_IOWR(0x58, ec_ioctl_reg_request_t) +#define EC_IOCTL_REG_REQUEST_STATE EC_IOWR(0x59, ec_ioctl_reg_request_t) +#define EC_IOCTL_REG_REQUEST_WRITE EC_IOWR(0x5a, ec_ioctl_reg_request_t) +#define EC_IOCTL_REG_REQUEST_READ EC_IOWR(0x5b, ec_ioctl_reg_request_t) +#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x5c, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x5d, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_READ EC_IOW(0x5e, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x5f, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_WRITE EC_IOWR(0x60, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_EXEC EC_IOWR(0x61, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_DATA EC_IOWR(0x62, ec_ioctl_voe_t) +#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x63, size_t) /****************************************************************************/ @@ -608,6 +611,37 @@ typedef struct { /****************************************************************************/ +#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 --git a/master/mailbox.h b/master/mailbox.h index 89475f3f..e9de78cf 100644 --- a/master/mailbox.h +++ b/master/mailbox.h @@ -38,8 +38,10 @@ #define EC_MBOX_HEADER_SIZE 6 /** Mailbox types. + * + * These are used in the 'Type' field of the mailbox header. */ -enum ec_mbox_types { +enum { EC_MBOX_TYPE_EOE = 0x02, EC_MBOX_TYPE_COE = 0x03, EC_MBOX_TYPE_FOE = 0x04, diff --git a/master/slave.c b/master/slave.c index 3773fe06..83ebf084 100644 --- a/master/slave.c +++ b/master/slave.c @@ -147,6 +147,7 @@ void ec_slave_init( 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); @@ -203,6 +204,17 @@ void ec_slave_clear(ec_slave_t *slave /**< EtherCAT slave */) request->state = EC_INT_REQUEST_FAILURE; } +#ifdef EC_EOE + 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; + } +#endif + wake_up_all(&slave->master->request_queue); if (slave->config) { diff --git a/master/slave.h b/master/slave.h index f367f844..4e113e28 100644 --- a/master/slave.h +++ b/master/slave.h @@ -220,8 +220,9 @@ struct ec_slave 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 --git a/tool/CommandIp.cpp b/tool/CommandIp.cpp new file mode 100644 index 00000000..21314fce --- /dev/null +++ b/tool/CommandIp.cpp @@ -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 --git a/tool/CommandIp.h b/tool/CommandIp.h new file mode 100644 index 00000000..ff8d7f1a --- /dev/null +++ b/tool/CommandIp.h @@ -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: + void parseMac(unsigned char [6], const string &); + void parseIpv4Prefix(ec_ioctl_slave_eoe_ip_t *, + const string &); + void resolveIpv4(uint32_t *, const string &); +}; + +/****************************************************************************/ + +#endif diff --git a/tool/Makefile.am b/tool/Makefile.am index c5935631..27bce15c 100644 --- a/tool/Makefile.am +++ b/tool/Makefile.am @@ -66,9 +66,9 @@ ethercat_SOURCES = \ sii_crc.cpp if ENABLE_EOE -ethercat_SOURCES += CommandEoe.cpp +ethercat_SOURCES += CommandEoe.cpp CommandIp.cpp else -EXTRA_DIST += CommandEoe.cpp +EXTRA_DIST += CommandEoe.cpp CommandIp.cpp endif noinst_HEADERS = \ @@ -108,9 +108,9 @@ noinst_HEADERS = \ sii_crc.h if ENABLE_EOE -noinst_HEADERS += CommandEoe.h +noinst_HEADERS += CommandEoe.h CommandIp.h else -EXTRA_DIST += CommandEoe.h +EXTRA_DIST += CommandEoe.h CommandIp.h endif REV = `if test -s $(top_srcdir)/revision; then \ diff --git a/tool/MasterDevice.cpp b/tool/MasterDevice.cpp index d24e56a0..4d67453f 100644 --- a/tool/MasterDevice.cpp +++ b/tool/MasterDevice.cpp @@ -602,3 +602,20 @@ void MasterDevice::writeSoe(ec_ioctl_slave_soe_write_t *data) } /****************************************************************************/ + +#ifdef EC_EOE +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); + } + } +} +#endif + +/****************************************************************************/ diff --git a/tool/MasterDevice.h b/tool/MasterDevice.h index c7f3a177..0643eda7 100644 --- a/tool/MasterDevice.h +++ b/tool/MasterDevice.h @@ -86,6 +86,25 @@ class MasterDeviceSoeException: /****************************************************************************/ +#ifdef EC_EOE +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) {}; +}; +#endif + +/****************************************************************************/ + class MasterDevice { public: @@ -138,6 +157,7 @@ class MasterDevice #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 --git a/tool/main.cpp b/tool/main.cpp index 4589ac0b..7505bdeb 100644 --- a/tool/main.cpp +++ b/tool/main.cpp @@ -41,6 +41,9 @@ using namespace std; #include "CommandFoeRead.h" #include "CommandFoeWrite.h" #include "CommandGraph.h" +#ifdef EC_EOE +# include "CommandIp.h" +#endif #include "CommandMaster.h" #include "CommandPdos.h" #include "CommandRegRead.h" @@ -282,6 +285,9 @@ int main(int argc, char **argv) commandList.push_back(new CommandFoeRead()); commandList.push_back(new CommandFoeWrite()); commandList.push_back(new CommandGraph()); +#ifdef EC_EOE + commandList.push_back(new CommandIp()); +#endif commandList.push_back(new CommandMaster()); commandList.push_back(new CommandPdos()); commandList.push_back(new CommandRegRead());