Merge branch 'ethercat-backport_setip' into 'devel-1.6'
Backport Set IP command from master See merge request etherlab.org/ethercat!112
This commit is contained in:
commit
585070576c
|
|
@ -21,6 +21,7 @@ COMMANDS := \
|
|||
foe_read \
|
||||
foe_write \
|
||||
graph \
|
||||
ip \
|
||||
master \
|
||||
pdos \
|
||||
reg_read \
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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 <linux/module.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -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 <linux/list.h>
|
||||
#include <linux/etherdevice.h> // 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
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
};
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
/****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
186
master/ioctl.h
186
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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
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] <ARGS>" << 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 <IPv4>[/prefix] IP address (optionally with" << endl
|
||||
<< " decimal subnet prefix)" << endl
|
||||
<< " link <MAC> Link-layer address (may contain" << endl
|
||||
<< " colons or hyphens)" << endl
|
||||
<< " default <IPv4> Default gateway" << endl
|
||||
<< " dns <IPv4> DNS server" << endl
|
||||
<< " name <hostname> 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 <alias>" << endl
|
||||
<< " --position -p <pos> 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);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
|
@ -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
|
||||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
/****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -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;}
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
Loading…
Reference in New Issue