Implemented EoE Set IP parameter request via command-line tool.
--- a/master/Kbuild.in Thu Nov 06 08:55:35 2014 +0100
+++ b/master/Kbuild.in Wed Nov 12 14:42:17 2014 +0100
@@ -40,10 +40,12 @@
datagram_pair.o \
device.o \
domain.o \
+ eoe_request.o \
fmmu_config.o \
foe_request.o \
fsm_change.o \
fsm_coe.o \
+ fsm_eoe.o \
fsm_foe.o \
fsm_master.o \
fsm_pdo.o \
--- a/master/Makefile.am Thu Nov 06 08:55:35 2014 +0100
+++ b/master/Makefile.am Wed Nov 12 14:42:17 2014 +0100
@@ -37,12 +37,14 @@
device.c device.h \
domain.c domain.h \
doxygen.c \
+ eoe_request.c eoe_request.h \
ethernet.c ethernet.h \
fmmu_config.c fmmu_config.h \
foe.h \
foe_request.c foe_request.h \
fsm_change.c fsm_change.h \
fsm_coe.c fsm_coe.h \
+ fsm_eoe.c fsm_eoe.h \
fsm_foe.c fsm_foe.h \
fsm_master.c fsm_master.h \
fsm_pdo.c fsm_pdo.h \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/master/eoe_request.c Wed Nov 12 14:42:17 2014 +0100
@@ -0,0 +1,71 @@
+/******************************************************************************
+ *
+ * $Id$
+ *
+ * Copyright (C) 2006-2014 Florian Pose, Ingenieurgemeinschaft IgH
+ *
+ * This file is part of the IgH EtherCAT Master.
+ *
+ * The IgH EtherCAT Master is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * The IgH EtherCAT Master is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with the IgH EtherCAT Master; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * ---
+ *
+ * The license mentioned above concerns the source code only. Using the
+ * EtherCAT technology and brand is only permitted in compliance with the
+ * industrial property and similar rights of Beckhoff Automation GmbH.
+ *
+ *****************************************************************************/
+
+/** \file
+ * Ethernet-over-EtherCAT request functions.
+ */
+
+/*****************************************************************************/
+
+#include <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;
+}
+
+/*****************************************************************************/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/master/eoe_request.h Wed Nov 12 14:42:17 2014 +0100
@@ -0,0 +1,77 @@
+/******************************************************************************
+ *
+ * $Id$
+ *
+ * Copyright (C) 2006-2014 Florian Pose, Ingenieurgemeinschaft IgH
+ *
+ * This file is part of the IgH EtherCAT Master.
+ *
+ * The IgH EtherCAT Master is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * The IgH EtherCAT Master is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with the IgH EtherCAT Master; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * ---
+ *
+ * The license mentioned above concerns the source code only. Using the
+ * EtherCAT technology and brand is only permitted in compliance with the
+ * industrial property and similar rights of Beckhoff Automation GmbH.
+ *
+ *****************************************************************************/
+
+/**
+ \file
+ EtherCAT EoE request structure.
+*/
+
+/*****************************************************************************/
+
+#ifndef __EC_EOE_REQUEST_H__
+#define __EC_EOE_REQUEST_H__
+
+#include <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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/master/fsm_eoe.c Wed Nov 12 14:42:17 2014 +0100
@@ -0,0 +1,485 @@
+/******************************************************************************
+ *
+ * $Id$
+ *
+ * Copyright (C) 2006-2014 Florian Pose, Ingenieurgemeinschaft IgH
+ *
+ * This file is part of the IgH EtherCAT Master.
+ *
+ * The IgH EtherCAT Master is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * The IgH EtherCAT Master is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with the IgH EtherCAT Master; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * ---
+ *
+ * The license mentioned above concerns the source code only. Using the
+ * EtherCAT technology and brand is only permitted in compliance with the
+ * industrial property and similar rights of Beckhoff Automation GmbH.
+ *
+ *****************************************************************************/
+
+/**
+ \file
+ EtherCAT EoE state machines.
+*/
+
+/*****************************************************************************/
+
+#include "globals.h"
+#include "master.h"
+#include "mailbox.h"
+#include "fsm_eoe.h"
+
+/*****************************************************************************/
+
+/** Maximum time to wait for a set IP parameter response.
+ */
+#define EC_EOE_RESPONSE_TIMEOUT 3000 // [ms]
+
+/*****************************************************************************/
+
+void ec_fsm_eoe_set_ip_start(ec_fsm_eoe_t *, ec_datagram_t *);
+void ec_fsm_eoe_set_ip_request(ec_fsm_eoe_t *, ec_datagram_t *);
+void ec_fsm_eoe_set_ip_check(ec_fsm_eoe_t *, ec_datagram_t *);
+void ec_fsm_eoe_set_ip_response(ec_fsm_eoe_t *, ec_datagram_t *);
+
+void ec_fsm_eoe_end(ec_fsm_eoe_t *, ec_datagram_t *);
+void ec_fsm_eoe_error(ec_fsm_eoe_t *, ec_datagram_t *);
+
+/*****************************************************************************/
+
+/** Constructor.
+ */
+void ec_fsm_eoe_init(
+ ec_fsm_eoe_t *fsm /**< finite state machine */
+ )
+{
+ fsm->slave = NULL;
+ fsm->retries = 0;
+ fsm->state = NULL;
+ fsm->datagram = NULL;
+ fsm->jiffies_start = 0;
+ fsm->request = NULL;
+}
+
+/*****************************************************************************/
+
+/** Destructor.
+ */
+void ec_fsm_eoe_clear(
+ ec_fsm_eoe_t *fsm /**< finite state machine */
+ )
+{
+}
+
+/*****************************************************************************/
+
+/** Starts to set the EoE IP partameters of a slave.
+ */
+void ec_fsm_eoe_set_ip_param(
+ ec_fsm_eoe_t *fsm, /**< State machine. */
+ ec_slave_t *slave, /**< EtherCAT slave. */
+ ec_eoe_request_t *request /**< EoE request. */
+ )
+{
+ fsm->slave = slave;
+ fsm->request = request;
+ fsm->state = ec_fsm_eoe_set_ip_start;
+}
+
+/*****************************************************************************/
+
+/** Executes the current state of the state machine.
+ *
+ * \return 1 if the datagram was used, else 0.
+ */
+int ec_fsm_eoe_exec(
+ ec_fsm_eoe_t *fsm, /**< finite state machine */
+ ec_datagram_t *datagram /**< Datagram to use. */
+ )
+{
+ int datagram_used = 0;
+
+ if (fsm->datagram &&
+ (fsm->datagram->state == EC_DATAGRAM_INIT ||
+ fsm->datagram->state == EC_DATAGRAM_QUEUED ||
+ fsm->datagram->state == EC_DATAGRAM_SENT)) {
+ // datagram not received yet
+ return datagram_used;
+ }
+
+ fsm->state(fsm, datagram);
+
+ datagram_used =
+ fsm->state != ec_fsm_eoe_end && fsm->state != ec_fsm_eoe_error;
+
+ if (datagram_used) {
+ fsm->datagram = datagram;
+ } else {
+ fsm->datagram = NULL;
+ }
+
+ return datagram_used;
+}
+
+/*****************************************************************************/
+
+/** Returns, if the state machine terminated with success.
+ *
+ * \return non-zero if successful.
+ */
+int ec_fsm_eoe_success(const ec_fsm_eoe_t *fsm /**< Finite state machine */)
+{
+ return fsm->state == ec_fsm_eoe_end;
+}
+
+/******************************************************************************
+ * EoE set IP parameter state machine
+ *****************************************************************************/
+
+/** Prepare a set IP parameters operation.
+ *
+ * \return 0 on success, otherwise a negative error code.
+ */
+int ec_fsm_eoe_prepare_set(
+ ec_fsm_eoe_t *fsm, /**< finite state machine */
+ ec_datagram_t *datagram /**< Datagram to use. */
+ )
+{
+ uint8_t *data, *cur;
+ ec_slave_t *slave = fsm->slave;
+ ec_master_t *master = slave->master;
+ ec_eoe_request_t *req = fsm->request;
+ size_t size = 8;
+
+ if (req->mac_address_included) {
+ size += ETH_ALEN;
+ }
+
+ if (req->ip_address_included) {
+ size += 4;
+ }
+
+ if (req->subnet_mask_included) {
+ size += 4;
+ }
+
+ if (req->gateway_included) {
+ size += 4;
+ }
+
+ if (req->dns_included) {
+ size += 4;
+ }
+
+ if (req->name_included) {
+ size += EC_MAX_HOSTNAME_SIZE;
+ }
+
+ data = ec_slave_mbox_prepare_send(slave, datagram, EC_MBOX_TYPE_EOE,
+ size);
+ if (IS_ERR(data)) {
+ return PTR_ERR(data);
+ }
+
+ EC_WRITE_U8(data, EC_EOE_FRAMETYPE_SET_IP_REQ); // Set IP parameter req.
+ EC_WRITE_U8(data + 1, 0x01); // last fragment, no timestamps
+ EC_WRITE_U16(data + 2, 0x0000); // fragment no., offset, frame no.
+
+ EC_WRITE_U32(data + 4,
+ ((req->mac_address_included != 0) << 0) |
+ ((req->ip_address_included != 0) << 1) |
+ ((req->subnet_mask_included != 0) << 2) |
+ ((req->gateway_included != 0) << 3) |
+ ((req->dns_included != 0) << 4) |
+ ((req->name_included != 0) << 5)
+ );
+
+ cur = data + 8;
+
+ if (req->mac_address_included) {
+ memcpy(cur, req->mac_address, ETH_ALEN);
+ cur += ETH_ALEN;
+ }
+
+ if (req->ip_address_included) {
+ memcpy(cur, &req->ip_address, 4);
+ cur += 4;
+ }
+
+ if (req->subnet_mask_included) {
+ memcpy(cur, &req->subnet_mask, 4);
+ cur += 4;
+ }
+
+ if (req->gateway_included) {
+ memcpy(cur, &req->gateway, 4);
+ cur += 4;
+ }
+
+ if (req->dns_included) {
+ memcpy(cur, &req->dns, 4);
+ cur += 4;
+ }
+
+ if (req->name_included) {
+ memcpy(cur, req->name, EC_MAX_HOSTNAME_SIZE);
+ cur += EC_MAX_HOSTNAME_SIZE;
+ }
+
+ if (master->debug_level) {
+ EC_SLAVE_DBG(slave, 0, "Set IP parameter request:\n");
+ ec_print_data(data, cur - data);
+ }
+
+ fsm->request->jiffies_sent = jiffies;
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+/** EoE state: SET IP START.
+ */
+void ec_fsm_eoe_set_ip_start(
+ ec_fsm_eoe_t *fsm, /**< finite state machine */
+ ec_datagram_t *datagram /**< Datagram to use. */
+ )
+{
+ ec_slave_t *slave = fsm->slave;
+
+ EC_SLAVE_DBG(slave, 1, "Setting IP parameters.\n");
+
+ if (!(slave->sii.mailbox_protocols & EC_MBOX_EOE)) {
+ EC_SLAVE_ERR(slave, "Slave does not support EoE!\n");
+ fsm->state = ec_fsm_eoe_error;
+ return;
+ }
+
+ if (ec_fsm_eoe_prepare_set(fsm, datagram)) {
+ fsm->state = ec_fsm_eoe_error;
+ return;
+ }
+
+ fsm->retries = EC_FSM_RETRIES;
+ fsm->state = ec_fsm_eoe_set_ip_request;
+}
+
+/*****************************************************************************/
+
+/** EoE state: SET IP REQUEST.
+ */
+void ec_fsm_eoe_set_ip_request(
+ ec_fsm_eoe_t *fsm, /**< finite state machine */
+ ec_datagram_t *datagram /**< Datagram to use. */
+ )
+{
+ ec_slave_t *slave = fsm->slave;
+
+ if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
+ if (ec_fsm_eoe_prepare_set(fsm, datagram)) {
+ fsm->state = ec_fsm_eoe_error;
+ }
+ return;
+ }
+
+ if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
+ fsm->state = ec_fsm_eoe_error;
+ EC_SLAVE_ERR(slave, "Failed to receive EoE set IP parameter"
+ " request: ");
+ ec_datagram_print_state(fsm->datagram);
+ return;
+ }
+
+ if (fsm->datagram->working_counter != 1) {
+ unsigned long diff_ms =
+ (jiffies - fsm->request->jiffies_sent) * 1000 / HZ;
+
+ if (!fsm->datagram->working_counter) {
+ if (diff_ms < EC_EOE_RESPONSE_TIMEOUT) {
+ // no response; send request datagram again
+ if (ec_fsm_eoe_prepare_set(fsm, datagram)) {
+ fsm->state = ec_fsm_eoe_error;
+ }
+ return;
+ }
+ }
+ fsm->state = ec_fsm_eoe_error;
+ EC_SLAVE_ERR(slave, "Reception of EoE set IP parameter request"
+ " failed after %lu ms: ", diff_ms);
+ ec_datagram_print_wc_error(fsm->datagram);
+ return;
+ }
+
+ fsm->jiffies_start = fsm->datagram->jiffies_sent;
+ ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
+ fsm->retries = EC_FSM_RETRIES;
+ fsm->state = ec_fsm_eoe_set_ip_check;
+}
+
+/*****************************************************************************/
+
+/** EoE state: SET IP CHECK.
+ */
+void ec_fsm_eoe_set_ip_check(
+ ec_fsm_eoe_t *fsm, /**< finite state machine */
+ ec_datagram_t *datagram /**< Datagram to use. */
+ )
+{
+ ec_slave_t *slave = fsm->slave;
+
+ if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
+ ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
+ return;
+ }
+
+ if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
+ fsm->state = ec_fsm_eoe_error;
+ EC_SLAVE_ERR(slave, "Failed to receive EoE mailbox check datagram: ");
+ ec_datagram_print_state(fsm->datagram);
+ return;
+ }
+
+ if (fsm->datagram->working_counter != 1) {
+ fsm->state = ec_fsm_eoe_error;
+ EC_SLAVE_ERR(slave, "Reception of EoE mailbox check"
+ " datagram failed: ");
+ ec_datagram_print_wc_error(fsm->datagram);
+ return;
+ }
+
+ if (!ec_slave_mbox_check(fsm->datagram)) {
+ unsigned long diff_ms =
+ (fsm->datagram->jiffies_received - fsm->jiffies_start) *
+ 1000 / HZ;
+ if (diff_ms >= EC_EOE_RESPONSE_TIMEOUT) {
+ fsm->state = ec_fsm_eoe_error;
+ EC_SLAVE_ERR(slave, "Timeout after %lu ms while waiting for"
+ " set IP parameter response.\n", diff_ms);
+ return;
+ }
+
+ ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
+ fsm->retries = EC_FSM_RETRIES;
+ return;
+ }
+
+ // fetch response
+ ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail.
+ fsm->retries = EC_FSM_RETRIES;
+ fsm->state = ec_fsm_eoe_set_ip_response;
+}
+
+/*****************************************************************************/
+
+/** EoE state: SET IP RESPONSE.
+ */
+void ec_fsm_eoe_set_ip_response(
+ ec_fsm_eoe_t *fsm, /**< finite state machine */
+ ec_datagram_t *datagram /**< Datagram to use. */
+ )
+{
+ ec_slave_t *slave = fsm->slave;
+ ec_master_t *master = slave->master;
+ uint8_t *data, mbox_prot, frame_type;
+ size_t rec_size;
+ ec_eoe_request_t *req = fsm->request;
+
+ if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
+ ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail.
+ return;
+ }
+
+ if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
+ fsm->state = ec_fsm_eoe_error;
+ EC_SLAVE_ERR(slave, "Failed to receive EoE read response datagram: ");
+ ec_datagram_print_state(fsm->datagram);
+ return;
+ }
+
+ if (fsm->datagram->working_counter != 1) {
+ fsm->state = ec_fsm_eoe_error;
+ EC_SLAVE_ERR(slave, "Reception of EoE read response failed: ");
+ ec_datagram_print_wc_error(fsm->datagram);
+ return;
+ }
+
+ data = ec_slave_mbox_fetch(slave, fsm->datagram, &mbox_prot, &rec_size);
+ if (IS_ERR(data)) {
+ fsm->state = ec_fsm_eoe_error;
+ return;
+ }
+
+ if (master->debug_level) {
+ EC_SLAVE_DBG(slave, 0, "Set IP parameter response:\n");
+ ec_print_data(data, rec_size);
+ }
+
+ if (mbox_prot != EC_MBOX_TYPE_EOE) {
+ fsm->state = ec_fsm_eoe_error;
+ EC_SLAVE_ERR(slave, "Received mailbox protocol 0x%02X as response.\n",
+ mbox_prot);
+ return;
+ }
+
+ if (rec_size < 4) {
+ fsm->state = ec_fsm_eoe_error;
+ EC_SLAVE_ERR(slave, "Received currupted EoE set IP parameter response"
+ " (%zu bytes)!\n", rec_size);
+ ec_print_data(data, rec_size);
+ return;
+ }
+
+ frame_type = EC_READ_U8(data) & 0x0f;
+
+ if (frame_type != EC_EOE_FRAMETYPE_SET_IP_RES) {
+ EC_SLAVE_ERR(slave, "Received no set IP parameter response"
+ " (frame type %x).\n", frame_type);
+ ec_print_data(data, rec_size);
+ fsm->state = ec_fsm_eoe_error;
+ return;
+ }
+
+ req->result = EC_READ_U16(data + 2);
+
+ if (req->result) {
+ fsm->state = ec_fsm_eoe_error;
+ EC_SLAVE_DBG(slave, 1, "EoE set IP parameters failed with result code"
+ " 0x%04X.\n", req->result);
+ } else {
+ fsm->state = ec_fsm_eoe_end; // success
+ }
+}
+
+/*****************************************************************************/
+
+/** State: ERROR.
+ */
+void ec_fsm_eoe_error(
+ ec_fsm_eoe_t *fsm, /**< finite state machine */
+ ec_datagram_t *datagram /**< Datagram to use. */
+ )
+{
+}
+
+/*****************************************************************************/
+
+/** State: END.
+ */
+void ec_fsm_eoe_end(
+ ec_fsm_eoe_t *fsm, /**< finite state machine */
+ ec_datagram_t *datagram /**< Datagram to use. */
+ )
+{
+}
+
+/*****************************************************************************/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/master/fsm_eoe.h Wed Nov 12 14:42:17 2014 +0100
@@ -0,0 +1,74 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ * Copyright (C) 2006-2014 Florian Pose, Ingenieurgemeinschaft IgH
+ *
+ * This file is part of the IgH EtherCAT Master.
+ *
+ * The IgH EtherCAT Master is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * The IgH EtherCAT Master is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with the IgH EtherCAT Master; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * ---
+ *
+ * The license mentioned above concerns the source code only. Using the
+ * EtherCAT technology and brand is only permitted in compliance with the
+ * industrial property and similar rights of Beckhoff Automation GmbH.
+ *
+ ****************************************************************************/
+
+/**
+ \file
+ EtherCAT EoE set IP parameter state machines.
+*/
+
+/****************************************************************************/
+
+#ifndef __EC_FSM_EOE_H__
+#define __EC_FSM_EOE_H__
+
+#include "globals.h"
+#include "datagram.h"
+#include "slave.h"
+#include "eoe_request.h"
+
+/****************************************************************************/
+
+typedef struct ec_fsm_eoe ec_fsm_eoe_t; /**< \see ec_fsm_eoe */
+
+/** Finite state machines for the Ethernet over EtherCAT protocol.
+ */
+struct ec_fsm_eoe {
+ ec_slave_t *slave; /**< slave the FSM runs on */
+ unsigned int retries; /**< retries upon datagram timeout */
+
+ void (*state)(ec_fsm_eoe_t *, ec_datagram_t *); /**< EoE state function */
+ ec_datagram_t *datagram; /**< Datagram used in the previous step. */
+ unsigned long jiffies_start; /**< Timestamp. */
+ ec_eoe_request_t *request; /**< EoE request */
+};
+
+/****************************************************************************/
+
+void ec_fsm_eoe_init(ec_fsm_eoe_t *);
+void ec_fsm_eoe_clear(ec_fsm_eoe_t *);
+
+void ec_fsm_eoe_set_ip_param(ec_fsm_eoe_t *, ec_slave_t *,
+ ec_eoe_request_t *);
+
+int ec_fsm_eoe_exec(ec_fsm_eoe_t *, ec_datagram_t *);
+int ec_fsm_eoe_success(const ec_fsm_eoe_t *);
+
+/****************************************************************************/
+
+#endif
--- a/master/fsm_slave.c Thu Nov 06 08:55:35 2014 +0100
+++ b/master/fsm_slave.c Wed Nov 12 14:42:17 2014 +0100
@@ -52,6 +52,8 @@
void ec_fsm_slave_state_foe_request(ec_fsm_slave_t *, ec_datagram_t *);
int ec_fsm_slave_action_process_soe(ec_fsm_slave_t *, ec_datagram_t *);
void ec_fsm_slave_state_soe_request(ec_fsm_slave_t *, ec_datagram_t *);
+int ec_fsm_slave_action_process_eoe(ec_fsm_slave_t *, ec_datagram_t *);
+void ec_fsm_slave_state_eoe_request(ec_fsm_slave_t *, ec_datagram_t *);
/*****************************************************************************/
@@ -71,11 +73,13 @@
fsm->reg_request = NULL;
fsm->foe_request = NULL;
fsm->soe_request = NULL;
+ fsm->eoe_request = NULL;
// Init sub-state-machines
ec_fsm_coe_init(&fsm->fsm_coe);
ec_fsm_foe_init(&fsm->fsm_foe);
ec_fsm_soe_init(&fsm->fsm_soe);
+ ec_fsm_eoe_init(&fsm->fsm_eoe);
}
/*****************************************************************************/
@@ -108,10 +112,16 @@
wake_up_all(&fsm->slave->master->request_queue);
}
+ if (fsm->eoe_request) {
+ fsm->soe_request->state = EC_INT_REQUEST_FAILURE;
+ wake_up_all(&fsm->slave->master->request_queue);
+ }
+
// clear sub-state machines
ec_fsm_coe_clear(&fsm->fsm_coe);
ec_fsm_foe_clear(&fsm->fsm_foe);
ec_fsm_soe_clear(&fsm->fsm_soe);
+ ec_fsm_eoe_clear(&fsm->fsm_eoe);
}
/*****************************************************************************/
@@ -210,6 +220,11 @@
if (ec_fsm_slave_action_process_soe(fsm, datagram)) {
return;
}
+
+ // Check for pending EoE IP parameter requests
+ if (ec_fsm_slave_action_process_eoe(fsm, datagram)) {
+ return;
+ }
}
/*****************************************************************************/
@@ -240,7 +255,7 @@
request->state = EC_INT_REQUEST_FAILURE;
wake_up_all(&slave->master->request_queue);
fsm->state = ec_fsm_slave_state_idle;
- return 1;
+ return 0;
}
if (slave->current_state == EC_SLAVE_STATE_INIT) {
@@ -248,7 +263,7 @@
request->state = EC_INT_REQUEST_FAILURE;
wake_up_all(&slave->master->request_queue);
fsm->state = ec_fsm_slave_state_idle;
- return 1;
+ return 0;
}
fsm->sdo_request = request;
@@ -342,7 +357,7 @@
wake_up_all(&slave->master->request_queue);
fsm->reg_request = NULL;
fsm->state = ec_fsm_slave_state_idle;
- return 1;
+ return 0;
}
// Found pending register request. Execute it!
@@ -444,7 +459,7 @@
request->state = EC_INT_REQUEST_FAILURE;
wake_up_all(&slave->master->request_queue);
fsm->state = ec_fsm_slave_state_idle;
- return 1;
+ return 0;
}
request->state = EC_INT_REQUEST_BUSY;
@@ -521,7 +536,7 @@
req->state = EC_INT_REQUEST_FAILURE;
wake_up_all(&slave->master->request_queue);
fsm->state = ec_fsm_slave_state_idle;
- return 1;
+ return 0;
}
if (slave->current_state == EC_SLAVE_STATE_INIT) {
@@ -580,3 +595,85 @@
}
/*****************************************************************************/
+
+/** Check for pending EoE IP parameter requests and process one.
+ *
+ * \return non-zero, if a request is processed.
+ */
+int ec_fsm_slave_action_process_eoe(
+ ec_fsm_slave_t *fsm, /**< Slave state machine. */
+ ec_datagram_t *datagram /**< Datagram to use. */
+ )
+{
+ ec_slave_t *slave = fsm->slave;
+ ec_eoe_request_t *request;
+
+ if (list_empty(&slave->eoe_requests)) {
+ return 0;
+ }
+
+ // take the first request to be processed
+ request = list_entry(slave->eoe_requests.next, ec_eoe_request_t, list);
+ list_del_init(&request->list); // dequeue
+
+ if (slave->current_state & EC_SLAVE_STATE_ACK_ERR) {
+ EC_SLAVE_WARN(slave, "Aborting EoE request,"
+ " slave has error flag set.\n");
+ request->state = EC_INT_REQUEST_FAILURE;
+ wake_up_all(&slave->master->request_queue);
+ fsm->state = ec_fsm_slave_state_idle;
+ return 0;
+ }
+
+ if (slave->current_state == EC_SLAVE_STATE_INIT) {
+ EC_SLAVE_WARN(slave, "Aborting EoE request, slave is in INIT.\n");
+ request->state = EC_INT_REQUEST_FAILURE;
+ wake_up_all(&slave->master->request_queue);
+ fsm->state = ec_fsm_slave_state_idle;
+ return 0;
+ }
+
+ fsm->eoe_request = request;
+ request->state = EC_INT_REQUEST_BUSY;
+
+ // Found pending request. Execute it!
+ EC_SLAVE_DBG(slave, 1, "Processing EoE request...\n");
+
+ // Start EoE command
+ fsm->state = ec_fsm_slave_state_eoe_request;
+ ec_fsm_eoe_set_ip_param(&fsm->fsm_eoe, slave, request);
+ ec_fsm_eoe_exec(&fsm->fsm_eoe, datagram); // execute immediately
+ return 1;
+}
+
+/*****************************************************************************/
+
+/** Slave state: EOE_REQUEST.
+ */
+void ec_fsm_slave_state_eoe_request(
+ ec_fsm_slave_t *fsm, /**< Slave state machine. */
+ ec_datagram_t *datagram /**< Datagram to use. */
+ )
+{
+ ec_slave_t *slave = fsm->slave;
+ ec_eoe_request_t *req = fsm->eoe_request;
+
+ if (ec_fsm_eoe_exec(&fsm->fsm_eoe, datagram)) {
+ return;
+ }
+
+ if (ec_fsm_eoe_success(&fsm->fsm_eoe)) {
+ req->state = EC_INT_REQUEST_SUCCESS;
+ EC_SLAVE_DBG(slave, 1, "Finished EoE request.\n");
+ }
+ else {
+ req->state = EC_INT_REQUEST_FAILURE;
+ EC_SLAVE_ERR(slave, "Failed to process EoE request.\n");
+ }
+
+ wake_up_all(&slave->master->request_queue);
+ fsm->eoe_request = NULL;
+ fsm->state = ec_fsm_slave_state_ready;
+}
+
+/*****************************************************************************/
--- a/master/fsm_slave.h Thu Nov 06 08:55:35 2014 +0100
+++ b/master/fsm_slave.h Wed Nov 12 14:42:17 2014 +0100
@@ -41,9 +41,11 @@
#include "datagram.h"
#include "sdo_request.h"
#include "reg_request.h"
+#include "eoe_request.h"
#include "fsm_coe.h"
#include "fsm_foe.h"
#include "fsm_soe.h"
+#include "fsm_eoe.h"
/*****************************************************************************/
@@ -62,10 +64,12 @@
ec_foe_request_t *foe_request; /**< FoE request to process. */
off_t foe_index; /**< Index to FoE write request data. */
ec_soe_request_t *soe_request; /**< SoE request to process. */
+ ec_eoe_request_t *eoe_request; /**< SoE request to process. */
ec_fsm_coe_t fsm_coe; /**< CoE state machine. */
ec_fsm_foe_t fsm_foe; /**< FoE state machine. */
ec_fsm_soe_t fsm_soe; /**< SoE state machine. */
+ ec_fsm_eoe_t fsm_eoe; /**< EoE state machine. */
};
/*****************************************************************************/
--- a/master/globals.h Thu Nov 06 08:55:35 2014 +0100
+++ b/master/globals.h Wed Nov 12 14:42:17 2014 +0100
@@ -115,6 +115,12 @@
**/
#define EC_DATAGRAM_NAME_SIZE 20
+/** Maximum hostname size.
+ *
+ * Used inside the EoE set IP parameter request.
+ */
+#define EC_MAX_HOSTNAME_SIZE 32
+
/** Slave state mask.
*
* Apply this mask to a slave state byte to get the slave state without
--- a/master/ioctl.c Thu Nov 06 08:55:35 2014 +0100
+++ b/master/ioctl.c Wed Nov 12 14:42:17 2014 +0100
@@ -1550,6 +1550,89 @@
/*****************************************************************************/
+/** Request EoE IP parameter setting.
+ *
+ * \return Zero on success, otherwise a negative error code.
+ */
+static ATTRIBUTES int ec_ioctl_slave_eoe_ip_param(
+ ec_master_t *master, /**< EtherCAT master. */
+ void *arg /**< ioctl() argument. */
+ )
+{
+ ec_ioctl_slave_eoe_ip_t io;
+ ec_eoe_request_t req;
+ ec_slave_t *slave;
+
+ if (copy_from_user(&io, (void __user *) arg, sizeof(io))) {
+ return -EFAULT;
+ }
+
+ // init EoE request
+ ec_eoe_request_init(&req);
+
+ req.mac_address_included = io.mac_address_included;
+ req.ip_address_included = io.ip_address_included;
+ req.subnet_mask_included = io.subnet_mask_included;
+ req.gateway_included = io.gateway_included;
+ req.dns_included = io.dns_included;
+ req.name_included = io.name_included;
+
+ memcpy(req.mac_address, io.mac_address, ETH_ALEN);
+ req.ip_address = io.ip_address;
+ req.subnet_mask = io.subnet_mask;
+ req.gateway = io.gateway;
+ req.dns = io.dns;
+ memcpy(req.name, io.name, EC_MAX_HOSTNAME_SIZE);
+
+ req.state = EC_INT_REQUEST_QUEUED;
+
+ if (down_interruptible(&master->master_sem)) {
+ return -EINTR;
+ }
+
+ if (!(slave = ec_master_find_slave(
+ master, 0, io.slave_position))) {
+ up(&master->master_sem);
+ EC_MASTER_ERR(master, "Slave %u does not exist!\n",
+ io.slave_position);
+ return -EINVAL;
+ }
+
+ EC_MASTER_DBG(master, 1, "Scheduling EoE request.\n");
+
+ // schedule request.
+ list_add_tail(&req.list, &slave->eoe_requests);
+
+ up(&master->master_sem);
+
+ // wait for processing through FSM
+ if (wait_event_interruptible(master->request_queue,
+ req.state != EC_INT_REQUEST_QUEUED)) {
+ // interrupted by signal
+ down(&master->master_sem);
+ if (req.state == EC_INT_REQUEST_QUEUED) {
+ // abort request
+ list_del(&req.list);
+ up(&master->master_sem);
+ return -EINTR;
+ }
+ up(&master->master_sem);
+ }
+
+ // wait until master FSM has finished processing
+ wait_event(master->request_queue, req.state != EC_INT_REQUEST_BUSY);
+
+ io.result = req.result;
+
+ if (copy_to_user((void __user *) arg, &io, sizeof(io))) {
+ return -EFAULT;
+ }
+
+ return req.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO;
+}
+
+/*****************************************************************************/
+
/** Request the master from userspace.
*
* \return Zero on success, otherwise a negative error code.
@@ -4205,6 +4288,13 @@
case EC_IOCTL_SLAVE_SOE_READ:
ret = ec_ioctl_slave_soe_read(master, arg);
break;
+ case EC_IOCTL_SLAVE_EOE_IP_PARAM:
+ if (!ctx->writable) {
+ ret = -EPERM;
+ break;
+ }
+ ret = ec_ioctl_slave_eoe_ip_param(master, arg);
+ break;
case EC_IOCTL_SLAVE_SOE_WRITE:
if (!ctx->writable) {
ret = -EPERM;
--- a/master/ioctl.h Thu Nov 06 08:55:35 2014 +0100
+++ b/master/ioctl.h Wed Nov 12 14:42:17 2014 +0100
@@ -56,7 +56,7 @@
*
* Increment this when changing the ioctl interface!
*/
-#define EC_IOCTL_VERSION_MAGIC 28
+#define EC_IOCTL_VERSION_MAGIC 29
// Command-line tool
#define EC_IOCTL_MODULE EC_IOR(0x00, ec_ioctl_module_t)
@@ -83,75 +83,76 @@
#define EC_IOCTL_SLAVE_FOE_WRITE EC_IOW(0x15, ec_ioctl_slave_foe_t)
#define EC_IOCTL_SLAVE_SOE_READ EC_IOWR(0x16, ec_ioctl_slave_soe_read_t)
#define EC_IOCTL_SLAVE_SOE_WRITE EC_IOWR(0x17, ec_ioctl_slave_soe_write_t)
-#define EC_IOCTL_CONFIG EC_IOWR(0x18, ec_ioctl_config_t)
-#define EC_IOCTL_CONFIG_PDO EC_IOWR(0x19, ec_ioctl_config_pdo_t)
-#define EC_IOCTL_CONFIG_PDO_ENTRY EC_IOWR(0x1a, ec_ioctl_config_pdo_entry_t)
-#define EC_IOCTL_CONFIG_SDO EC_IOWR(0x1b, ec_ioctl_config_sdo_t)
-#define EC_IOCTL_CONFIG_IDN EC_IOWR(0x1c, ec_ioctl_config_idn_t)
+#define EC_IOCTL_SLAVE_EOE_IP_PARAM EC_IOW(0x18, ec_ioctl_slave_eoe_ip_t)
+#define EC_IOCTL_CONFIG EC_IOWR(0x19, ec_ioctl_config_t)
+#define EC_IOCTL_CONFIG_PDO EC_IOWR(0x1a, ec_ioctl_config_pdo_t)
+#define EC_IOCTL_CONFIG_PDO_ENTRY EC_IOWR(0x1b, ec_ioctl_config_pdo_entry_t)
+#define EC_IOCTL_CONFIG_SDO EC_IOWR(0x1c, ec_ioctl_config_sdo_t)
+#define EC_IOCTL_CONFIG_IDN EC_IOWR(0x1d, ec_ioctl_config_idn_t)
#ifdef EC_EOE
-#define EC_IOCTL_EOE_HANDLER EC_IOWR(0x1d, ec_ioctl_eoe_handler_t)
+#define EC_IOCTL_EOE_HANDLER EC_IOWR(0x1e, ec_ioctl_eoe_handler_t)
#endif
// Application interface
-#define EC_IOCTL_REQUEST EC_IO(0x1e)
-#define EC_IOCTL_CREATE_DOMAIN EC_IO(0x1f)
-#define EC_IOCTL_CREATE_SLAVE_CONFIG EC_IOWR(0x20, ec_ioctl_config_t)
-#define EC_IOCTL_SELECT_REF_CLOCK EC_IOW(0x21, uint32_t)
-#define EC_IOCTL_ACTIVATE EC_IOR(0x22, ec_ioctl_master_activate_t)
-#define EC_IOCTL_DEACTIVATE EC_IO(0x23)
-#define EC_IOCTL_SEND EC_IO(0x24)
-#define EC_IOCTL_RECEIVE EC_IO(0x25)
-#define EC_IOCTL_MASTER_STATE EC_IOR(0x26, ec_master_state_t)
-#define EC_IOCTL_MASTER_LINK_STATE EC_IOWR(0x27, ec_ioctl_link_state_t)
-#define EC_IOCTL_APP_TIME EC_IOW(0x28, ec_ioctl_app_time_t)
-#define EC_IOCTL_SYNC_REF EC_IO(0x29)
-#define EC_IOCTL_SYNC_SLAVES EC_IO(0x2a)
-#define EC_IOCTL_REF_CLOCK_TIME EC_IOR(0x2b, uint32_t)
-#define EC_IOCTL_SYNC_MON_QUEUE EC_IO(0x2c)
-#define EC_IOCTL_SYNC_MON_PROCESS EC_IOR(0x2d, uint32_t)
-#define EC_IOCTL_RESET EC_IO(0x2e)
-#define EC_IOCTL_SC_SYNC EC_IOW(0x2f, ec_ioctl_config_t)
-#define EC_IOCTL_SC_WATCHDOG EC_IOW(0x30, ec_ioctl_config_t)
-#define EC_IOCTL_SC_ADD_PDO EC_IOW(0x31, ec_ioctl_config_pdo_t)
-#define EC_IOCTL_SC_CLEAR_PDOS EC_IOW(0x32, ec_ioctl_config_pdo_t)
-#define EC_IOCTL_SC_ADD_ENTRY EC_IOW(0x33, ec_ioctl_add_pdo_entry_t)
-#define EC_IOCTL_SC_CLEAR_ENTRIES EC_IOW(0x34, ec_ioctl_config_pdo_t)
-#define EC_IOCTL_SC_REG_PDO_ENTRY EC_IOWR(0x35, ec_ioctl_reg_pdo_entry_t)
-#define EC_IOCTL_SC_REG_PDO_POS EC_IOWR(0x36, ec_ioctl_reg_pdo_pos_t)
-#define EC_IOCTL_SC_DC EC_IOW(0x37, ec_ioctl_config_t)
-#define EC_IOCTL_SC_SDO EC_IOW(0x38, ec_ioctl_sc_sdo_t)
-#define EC_IOCTL_SC_EMERG_SIZE EC_IOW(0x39, ec_ioctl_sc_emerg_t)
-#define EC_IOCTL_SC_EMERG_POP EC_IOWR(0x3a, ec_ioctl_sc_emerg_t)
-#define EC_IOCTL_SC_EMERG_CLEAR EC_IOW(0x3b, ec_ioctl_sc_emerg_t)
-#define EC_IOCTL_SC_EMERG_OVERRUNS EC_IOWR(0x3c, ec_ioctl_sc_emerg_t)
-#define EC_IOCTL_SC_SDO_REQUEST EC_IOWR(0x3d, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SC_REG_REQUEST EC_IOWR(0x3e, ec_ioctl_reg_request_t)
-#define EC_IOCTL_SC_VOE EC_IOWR(0x3f, ec_ioctl_voe_t)
-#define EC_IOCTL_SC_STATE EC_IOWR(0x40, ec_ioctl_sc_state_t)
-#define EC_IOCTL_SC_IDN EC_IOW(0x41, ec_ioctl_sc_idn_t)
-#define EC_IOCTL_DOMAIN_SIZE EC_IO(0x42)
-#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x43)
-#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x44)
-#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x45)
-#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x46, ec_ioctl_domain_state_t)
-#define EC_IOCTL_SDO_REQUEST_INDEX EC_IOWR(0x47, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x48, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x49, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x4a, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x4b, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x4c, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_REG_REQUEST_DATA EC_IOWR(0x4d, ec_ioctl_reg_request_t)
-#define EC_IOCTL_REG_REQUEST_STATE EC_IOWR(0x4e, ec_ioctl_reg_request_t)
-#define EC_IOCTL_REG_REQUEST_WRITE EC_IOWR(0x4f, ec_ioctl_reg_request_t)
-#define EC_IOCTL_REG_REQUEST_READ EC_IOWR(0x50, ec_ioctl_reg_request_t)
-#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x51, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x52, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_READ EC_IOW(0x53, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x54, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_WRITE EC_IOWR(0x55, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_EXEC EC_IOWR(0x56, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_DATA EC_IOWR(0x57, ec_ioctl_voe_t)
-#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x58, size_t)
+#define EC_IOCTL_REQUEST EC_IO(0x1f)
+#define EC_IOCTL_CREATE_DOMAIN EC_IO(0x20)
+#define EC_IOCTL_CREATE_SLAVE_CONFIG EC_IOWR(0x21, ec_ioctl_config_t)
+#define EC_IOCTL_SELECT_REF_CLOCK EC_IOW(0x22, uint32_t)
+#define EC_IOCTL_ACTIVATE EC_IOR(0x23, ec_ioctl_master_activate_t)
+#define EC_IOCTL_DEACTIVATE EC_IO(0x24)
+#define EC_IOCTL_SEND EC_IO(0x25)
+#define EC_IOCTL_RECEIVE EC_IO(0x26)
+#define EC_IOCTL_MASTER_STATE EC_IOR(0x27, ec_master_state_t)
+#define EC_IOCTL_MASTER_LINK_STATE EC_IOWR(0x28, ec_ioctl_link_state_t)
+#define EC_IOCTL_APP_TIME EC_IOW(0x29, ec_ioctl_app_time_t)
+#define EC_IOCTL_SYNC_REF EC_IO(0x2a)
+#define EC_IOCTL_SYNC_SLAVES EC_IO(0x2b)
+#define EC_IOCTL_REF_CLOCK_TIME EC_IOR(0x2c, uint32_t)
+#define EC_IOCTL_SYNC_MON_QUEUE EC_IO(0x2d)
+#define EC_IOCTL_SYNC_MON_PROCESS EC_IOR(0x2e, uint32_t)
+#define EC_IOCTL_RESET EC_IO(0x2f)
+#define EC_IOCTL_SC_SYNC EC_IOW(0x30, ec_ioctl_config_t)
+#define EC_IOCTL_SC_WATCHDOG EC_IOW(0x31, ec_ioctl_config_t)
+#define EC_IOCTL_SC_ADD_PDO EC_IOW(0x32, ec_ioctl_config_pdo_t)
+#define EC_IOCTL_SC_CLEAR_PDOS EC_IOW(0x33, ec_ioctl_config_pdo_t)
+#define EC_IOCTL_SC_ADD_ENTRY EC_IOW(0x34, ec_ioctl_add_pdo_entry_t)
+#define EC_IOCTL_SC_CLEAR_ENTRIES EC_IOW(0x35, ec_ioctl_config_pdo_t)
+#define EC_IOCTL_SC_REG_PDO_ENTRY EC_IOWR(0x36, ec_ioctl_reg_pdo_entry_t)
+#define EC_IOCTL_SC_REG_PDO_POS EC_IOWR(0x37, ec_ioctl_reg_pdo_pos_t)
+#define EC_IOCTL_SC_DC EC_IOW(0x38, ec_ioctl_config_t)
+#define EC_IOCTL_SC_SDO EC_IOW(0x39, ec_ioctl_sc_sdo_t)
+#define EC_IOCTL_SC_EMERG_SIZE EC_IOW(0x3a, ec_ioctl_sc_emerg_t)
+#define EC_IOCTL_SC_EMERG_POP EC_IOWR(0x3b, ec_ioctl_sc_emerg_t)
+#define EC_IOCTL_SC_EMERG_CLEAR EC_IOW(0x3c, ec_ioctl_sc_emerg_t)
+#define EC_IOCTL_SC_EMERG_OVERRUNS EC_IOWR(0x3d, ec_ioctl_sc_emerg_t)
+#define EC_IOCTL_SC_SDO_REQUEST EC_IOWR(0x3e, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SC_REG_REQUEST EC_IOWR(0x3f, ec_ioctl_reg_request_t)
+#define EC_IOCTL_SC_VOE EC_IOWR(0x40, ec_ioctl_voe_t)
+#define EC_IOCTL_SC_STATE EC_IOWR(0x41, ec_ioctl_sc_state_t)
+#define EC_IOCTL_SC_IDN EC_IOW(0x42, ec_ioctl_sc_idn_t)
+#define EC_IOCTL_DOMAIN_SIZE EC_IO(0x43)
+#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x44)
+#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x45)
+#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x46)
+#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x47, ec_ioctl_domain_state_t)
+#define EC_IOCTL_SDO_REQUEST_INDEX EC_IOWR(0x48, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x49, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x4a, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x4b, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x4c, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x4d, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_REG_REQUEST_DATA EC_IOWR(0x4e, ec_ioctl_reg_request_t)
+#define EC_IOCTL_REG_REQUEST_STATE EC_IOWR(0x4f, ec_ioctl_reg_request_t)
+#define EC_IOCTL_REG_REQUEST_WRITE EC_IOWR(0x50, ec_ioctl_reg_request_t)
+#define EC_IOCTL_REG_REQUEST_READ EC_IOWR(0x51, ec_ioctl_reg_request_t)
+#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x52, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x53, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_READ EC_IOW(0x54, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x55, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_WRITE EC_IOWR(0x56, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_EXEC EC_IOWR(0x57, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_DATA EC_IOWR(0x58, ec_ioctl_voe_t)
+#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x59, size_t)
/*****************************************************************************/
@@ -590,6 +591,37 @@
/*****************************************************************************/
+#define EC_ETH_ALEN 6
+#ifdef ETH_ALEN
+#if ETH_ALEN != EC_ETH_ALEN
+#error Ethernet address length mismatch
+#endif
+#endif
+
+typedef struct {
+ // input
+ uint16_t slave_position;
+
+ uint8_t mac_address_included;
+ uint8_t ip_address_included;
+ uint8_t subnet_mask_included;
+ uint8_t gateway_included;
+ uint8_t dns_included;
+ uint8_t name_included;
+
+ unsigned char mac_address[EC_ETH_ALEN];
+ uint32_t ip_address;
+ uint32_t subnet_mask;
+ uint32_t gateway;
+ uint32_t dns;
+ char name[EC_MAX_HOSTNAME_SIZE];
+
+ // output
+ uint16_t result;
+} ec_ioctl_slave_eoe_ip_t;
+
+/*****************************************************************************/
+
typedef struct {
// outputs
void *process_data;
--- a/master/slave.c Thu Nov 06 08:55:35 2014 +0100
+++ b/master/slave.c Wed Nov 12 14:42:17 2014 +0100
@@ -155,6 +155,7 @@
INIT_LIST_HEAD(&slave->reg_requests);
INIT_LIST_HEAD(&slave->foe_requests);
INIT_LIST_HEAD(&slave->soe_requests);
+ INIT_LIST_HEAD(&slave->eoe_requests);
// create state machine object
ec_fsm_slave_init(&slave->fsm, slave);
@@ -211,6 +212,15 @@
request->state = EC_INT_REQUEST_FAILURE;
}
+ while (!list_empty(&slave->eoe_requests)) {
+ ec_eoe_request_t *request =
+ list_entry(slave->eoe_requests.next, ec_eoe_request_t, list);
+ list_del_init(&request->list); // dequeue
+ EC_SLAVE_WARN(slave, "Discarding EoE request,"
+ " slave about to be deleted.\n");
+ request->state = EC_INT_REQUEST_FAILURE;
+ }
+
wake_up_all(&slave->master->request_queue);
if (slave->config) {
--- a/master/slave.h Thu Nov 06 08:55:35 2014 +0100
+++ b/master/slave.h Wed Nov 12 14:42:17 2014 +0100
@@ -228,8 +228,9 @@
struct list_head sdo_requests; /**< SDO access requests. */
struct list_head reg_requests; /**< Register access requests. */
- struct list_head foe_requests; /**< FoE write requests. */
- struct list_head soe_requests; /**< SoE write requests. */
+ struct list_head foe_requests; /**< FoE requests. */
+ struct list_head soe_requests; /**< SoE requests. */
+ struct list_head eoe_requests; /**< EoE set IP parameter requests. */
ec_fsm_slave_t fsm; /**< Slave state machine. */
};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandIp.cpp Wed Nov 12 14:42:17 2014 +0100
@@ -0,0 +1,258 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ * Copyright (C) 2006-2014 Florian Pose, Ingenieurgemeinschaft IgH
+ *
+ * This file is part of the IgH EtherCAT Master.
+ *
+ * The IgH EtherCAT Master is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * The IgH EtherCAT Master is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with the IgH EtherCAT Master; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * ---
+ *
+ * The license mentioned above concerns the source code only. Using the
+ * EtherCAT technology and brand is only permitted in compliance with the
+ * industrial property and similar rights of Beckhoff Automation GmbH.
+ *
+ * vim: expandtab
+ *
+ ****************************************************************************/
+
+#include <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);
+}
+
+/****************************************************************************/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandIp.h Wed Nov 12 14:42:17 2014 +0100
@@ -0,0 +1,55 @@
+/*****************************************************************************
+ *
+ * $Id$
+ *
+ * Copyright (C) 2006-2014 Florian Pose, Ingenieurgemeinschaft IgH
+ *
+ * This file is part of the IgH EtherCAT Master.
+ *
+ * The IgH EtherCAT Master is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * The IgH EtherCAT Master is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with the IgH EtherCAT Master; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * ---
+ *
+ * The license mentioned above concerns the source code only. Using the
+ * EtherCAT technology and brand is only permitted in compliance with the
+ * industrial property and similar rights of Beckhoff Automation GmbH.
+ *
+ ****************************************************************************/
+
+#ifndef __COMMANDIP_H__
+#define __COMMANDIP_H__
+
+#include "Command.h"
+
+/****************************************************************************/
+
+class CommandIp:
+ public Command
+{
+ public:
+ CommandIp();
+
+ string helpString(const string &) const;
+ void execute(const StringVector &);
+
+ protected:
+ static void parseMac(unsigned char [6], const string &);
+ static void parseIpv4Prefix(ec_ioctl_slave_eoe_ip_t *,
+ const string &);
+ static void resolveIpv4(uint32_t *, const string &);
+};
+
+/****************************************************************************/
+
+#endif
--- a/tool/Makefile.am Thu Nov 06 08:55:35 2014 +0100
+++ b/tool/Makefile.am Wed Nov 12 14:42:17 2014 +0100
@@ -48,6 +48,7 @@
CommandFoeRead.cpp \
CommandFoeWrite.cpp \
CommandGraph.cpp \
+ CommandIp.cpp \
CommandMaster.cpp \
CommandPdos.cpp \
CommandRegRead.cpp \
@@ -90,6 +91,7 @@
CommandFoeRead.h \
CommandFoeWrite.h \
CommandGraph.h \
+ CommandIp.h \
CommandMaster.h \
CommandPdos.h \
CommandRegRead.h \
--- a/tool/MasterDevice.cpp Thu Nov 06 08:55:35 2014 +0100
+++ b/tool/MasterDevice.cpp Wed Nov 12 14:42:17 2014 +0100
@@ -585,4 +585,19 @@
}
}
+/****************************************************************************/
+
+void MasterDevice::setIpParam(ec_ioctl_slave_eoe_ip_t *data)
+{
+ if (ioctl(fd, EC_IOCTL_SLAVE_EOE_IP_PARAM, data) < 0) {
+ if (errno == EIO && data->result) {
+ throw MasterDeviceEoeException(data->result);
+ } else {
+ stringstream err;
+ err << "Failed to set IP parameters: " << strerror(errno);
+ throw MasterDeviceException(err);
+ }
+ }
+}
+
/*****************************************************************************/
--- a/tool/MasterDevice.h Thu Nov 06 08:55:35 2014 +0100
+++ b/tool/MasterDevice.h Wed Nov 12 14:42:17 2014 +0100
@@ -94,6 +94,23 @@
/****************************************************************************/
+class MasterDeviceEoeException:
+ public MasterDeviceException
+{
+ friend class MasterDevice;
+
+ public:
+ uint16_t result;
+
+ protected:
+ /** Constructor with error code parameter. */
+ MasterDeviceEoeException(uint16_t result):
+ MasterDeviceException("EoE set IP parameter failed."),
+ result(result) {};
+};
+
+/****************************************************************************/
+
class MasterDevice
{
public:
@@ -144,6 +161,7 @@
#endif
void readSoe(ec_ioctl_slave_soe_read_t *);
void writeSoe(ec_ioctl_slave_soe_write_t *);
+ void setIpParam(ec_ioctl_slave_eoe_ip_t *);
unsigned int getMasterCount() const {return masterCount;}
--- a/tool/main.cpp Thu Nov 06 08:55:35 2014 +0100
+++ b/tool/main.cpp Wed Nov 12 14:42:17 2014 +0100
@@ -48,6 +48,7 @@
#include "CommandFoeRead.h"
#include "CommandFoeWrite.h"
#include "CommandGraph.h"
+#include "CommandIp.h"
#include "CommandMaster.h"
#include "CommandPdos.h"
#include "CommandRegRead.h"
@@ -288,6 +289,7 @@
commandList.push_back(new CommandFoeRead());
commandList.push_back(new CommandFoeWrite());
commandList.push_back(new CommandGraph());
+ commandList.push_back(new CommandIp());
commandList.push_back(new CommandMaster());
commandList.push_back(new CommandPdos());
commandList.push_back(new CommandRegRead());