From 60ebe661a634a2c3fd106bd9c7fa8fc3516eb664 Mon Sep 17 00:00:00 2001 From: Florian Pose Date: Wed, 5 Nov 2014 19:04:36 +0100 Subject: [PATCH 01/13] EoE frame types. --- master/ethernet.c | 4 ++-- master/ethernet.h | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/master/ethernet.c b/master/ethernet.c index a997f00d..fd3e679b 100644 --- a/master/ethernet.c +++ b/master/ethernet.c @@ -320,7 +320,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_FRAG_REQ); EC_WRITE_U8 (data + 1, last_fragment); EC_WRITE_U16(data + 2, ((eoe->tx_fragment_number & 0x3F) | (complete_offset & 0x3F) << 6 | @@ -507,7 +507,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_FRAG_REQ) { #if EOE_DEBUG_LEVEL >= 1 EC_SLAVE_WARN(eoe->slave, "%s: Other frame received." " Dropping.\n", eoe->dev->name); diff --git a/master/ethernet.h b/master/ethernet.h index b0b3860c..eab353ec 100644 --- a/master/ethernet.h +++ b/master/ethernet.h @@ -52,6 +52,18 @@ /*****************************************************************************/ +/** EoE frame types. + */ +enum { + EC_EOE_FRAMETYPE_FRAG_REQ = 0x00, /** EoE Fragment Request. */ + EC_EOE_FRAMETYPE_INIT_REQ = 0x02, /** Initiate EoE Request. */ + EC_EOE_FRAMETYPE_INIT_RES = 0x03, /** Initiate EoE Response. */ + EC_EOE_FRAMETYPE_FILT_REQ = 0x04, /** Set Address Filter Request. */ + EC_EOE_FRAMETYPE_FILT_RES = 0x05, /** Set Address Filter Response. */ +}; + +/*****************************************************************************/ + /** Queued frame structure. */ From d1df6520bac0600aa239e2889b0cbe243d496b9a Mon Sep 17 00:00:00 2001 From: Florian Pose Date: Thu, 6 Nov 2014 08:53:11 +0100 Subject: [PATCH 02/13] Cleaned up EoE frame type definitions. --- master/ethernet.c | 4 ++-- master/ethernet.h | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/master/ethernet.c b/master/ethernet.c index fd3e679b..0eb0e964 100644 --- a/master/ethernet.c +++ b/master/ethernet.c @@ -320,7 +320,7 @@ int ec_eoe_send(ec_eoe_t *eoe /**< EoE handler */) if (IS_ERR(data)) return PTR_ERR(data); - EC_WRITE_U8 (data, EC_EOE_FRAMETYPE_FRAG_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 | @@ -507,7 +507,7 @@ void ec_eoe_state_rx_fetch(ec_eoe_t *eoe /**< EoE handler */) frame_type = EC_READ_U16(data) & 0x000F; - if (frame_type != EC_EOE_FRAMETYPE_FRAG_REQ) { + if (frame_type != EC_EOE_FRAMETYPE_INIT_REQ) { // EoE Fragment Data #if EOE_DEBUG_LEVEL >= 1 EC_SLAVE_WARN(eoe->slave, "%s: Other frame received." " Dropping.\n", eoe->dev->name); diff --git a/master/ethernet.h b/master/ethernet.h index eab353ec..024ec9a3 100644 --- a/master/ethernet.h +++ b/master/ethernet.h @@ -55,11 +55,11 @@ /** EoE frame types. */ enum { - EC_EOE_FRAMETYPE_FRAG_REQ = 0x00, /** EoE Fragment Request. */ - EC_EOE_FRAMETYPE_INIT_REQ = 0x02, /** Initiate EoE Request. */ - EC_EOE_FRAMETYPE_INIT_RES = 0x03, /** Initiate EoE Response. */ - EC_EOE_FRAMETYPE_FILT_REQ = 0x04, /** Set Address Filter Request. */ - EC_EOE_FRAMETYPE_FILT_RES = 0x05, /** Set Address Filter Response. */ + 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. */ }; /*****************************************************************************/ From 41bc600cef4097d2e26c71e77c8e9322e8044a56 Mon Sep 17 00:00:00 2001 From: Florian Pose Date: Thu, 6 Nov 2014 08:54:14 +0100 Subject: [PATCH 03/13] Removed obsolete SoE type name. --- master/fsm_soe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/master/fsm_soe.c b/master/fsm_soe.c index 623d4f5c..bcc25105 100644 --- a/master/fsm_soe.c +++ b/master/fsm_soe.c @@ -41,7 +41,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. */ From 5a255fce3d492f43f8455815534a282724235d37 Mon Sep 17 00:00:00 2001 From: Florian Pose Date: Thu, 6 Nov 2014 08:53:45 +0100 Subject: [PATCH 04/13] Removed obsolete FoE type name. --- master/fsm_foe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/master/fsm_foe.c b/master/fsm_foe.c index b722fd7c..417b72d3 100644 --- a/master/fsm_foe.c +++ b/master/fsm_foe.c @@ -66,7 +66,7 @@ enum { EC_FOE_OPCODE_ACK = 4, /**< Acknowledge. */ EC_FOE_OPCODE_ERR = 5, /**< Error. */ EC_FOE_OPCODE_BUSY = 6 /**< Busy. */ -} ec_foe_opcode_t; +}; /*****************************************************************************/ From 0e25f6d80fcd348b1d2fe1db706c3542c92b8195 Mon Sep 17 00:00:00 2001 From: Florian Pose Date: Thu, 6 Nov 2014 08:55:35 +0100 Subject: [PATCH 05/13] Removed obsolete mailbox type name and clarified documentation. --- master/globals.h | 3 +++ master/mailbox.h | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/master/globals.h b/master/globals.h index a0c820df..69f313bf 100644 --- a/master/globals.h +++ b/master/globals.h @@ -130,6 +130,9 @@ typedef enum { } ec_slave_state_t; /** Supported mailbox protocols. + * + * Not to mix up with the mailbox type field in the mailbox header defined in + * master/mailbox.h. */ enum { EC_MBOX_AOE = 0x01, /**< ADS over EtherCAT */ diff --git a/master/mailbox.h b/master/mailbox.h index db130ff1..18a5d4ab 100644 --- a/master/mailbox.h +++ b/master/mailbox.h @@ -46,8 +46,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, From 4d47f0b32856ec600f2a4f9fe0f1909e6811e8f4 Mon Sep 17 00:00:00 2001 From: Florian Pose Date: Wed, 12 Nov 2014 14:42:17 +0100 Subject: [PATCH 06/13] Implemented EoE Set IP parameter request via command-line tool. --- master/Kbuild.in | 2 + master/Makefile.am | 2 + master/eoe_request.c | 71 +++++++ master/eoe_request.h | 77 +++++++ master/fsm_eoe.c | 485 ++++++++++++++++++++++++++++++++++++++++++ master/fsm_eoe.h | 74 +++++++ master/fsm_slave.c | 107 +++++++++- master/fsm_slave.h | 4 + master/globals.h | 6 + master/ioctl.c | 90 ++++++++ master/ioctl.h | 172 +++++++++------ master/slave.c | 10 + master/slave.h | 5 +- tool/CommandIp.cpp | 258 ++++++++++++++++++++++ tool/CommandIp.h | 55 +++++ tool/Makefile.am | 2 + tool/MasterDevice.cpp | 15 ++ tool/MasterDevice.h | 18 ++ tool/main.cpp | 2 + 19 files changed, 1379 insertions(+), 76 deletions(-) create mode 100644 master/eoe_request.c create mode 100644 master/eoe_request.h create mode 100644 master/fsm_eoe.c create mode 100644 master/fsm_eoe.h create mode 100644 tool/CommandIp.cpp create mode 100644 tool/CommandIp.h diff --git a/master/Kbuild.in b/master/Kbuild.in index 98b9e6cd..14f6e300 100644 --- a/master/Kbuild.in +++ b/master/Kbuild.in @@ -40,11 +40,13 @@ ec_master-objs := \ datagram_pair.o \ device.o \ domain.o \ + eoe_request.o \ flag.o \ fmmu_config.o \ foe_request.o \ fsm_change.o \ fsm_coe.o \ + fsm_eoe.o \ fsm_foe.o \ fsm_master.o \ fsm_pdo.o \ diff --git a/master/Makefile.am b/master/Makefile.am index cbd7cf59..505b6a7f 100644 --- a/master/Makefile.am +++ b/master/Makefile.am @@ -38,12 +38,14 @@ noinst_HEADERS = \ device.c device.h \ domain.c domain.h \ doxygen.c \ + eoe_request.c eoe_request.h \ ethernet.c ethernet.h \ fmmu_config.c fmmu_config.h \ foe.h \ foe_request.c foe_request.h \ fsm_change.c fsm_change.h \ fsm_coe.c fsm_coe.h \ + fsm_eoe.c fsm_eoe.h \ fsm_foe.c fsm_foe.h \ fsm_master.c fsm_master.h \ fsm_pdo.c fsm_pdo.h \ diff --git a/master/eoe_request.c b/master/eoe_request.c new file mode 100644 index 00000000..90b96233 --- /dev/null +++ b/master/eoe_request.c @@ -0,0 +1,71 @@ +/****************************************************************************** + * + * $Id$ + * + * Copyright (C) 2006-2014 Florian Pose, Ingenieurgemeinschaft IgH + * + * This file is part of the IgH EtherCAT Master. + * + * The IgH EtherCAT Master is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * The IgH EtherCAT Master is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with the IgH EtherCAT Master; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * --- + * + * The license mentioned above concerns the source code only. Using the + * EtherCAT technology and brand is only permitted in compliance with the + * industrial property and similar rights of Beckhoff Automation GmbH. + * + *****************************************************************************/ + +/** \file + * Ethernet-over-EtherCAT request functions. + */ + +/*****************************************************************************/ + +#include +#include +#include + +#include "eoe_request.h" + +/*****************************************************************************/ + +/** EoE request constructor. + */ +void ec_eoe_request_init( + ec_eoe_request_t *req /**< EoE request. */ + ) +{ + INIT_LIST_HEAD(&req->list); + req->state = EC_INT_REQUEST_INIT; + req->jiffies_sent = 0U; + + req->mac_address_included = 0; + req->ip_address_included = 0; + req->subnet_mask_included = 0; + req->gateway_included = 0; + req->dns_included = 0; + req->name_included = 0; + + memset(req->mac_address, 0x00, ETH_ALEN); + req->ip_address = 0; + req->subnet_mask = 0; + req->gateway = 0; + req->dns = 0; + req->name[0] = 0x00; + + req->result = 0x0000; +} + +/*****************************************************************************/ diff --git a/master/eoe_request.h b/master/eoe_request.h new file mode 100644 index 00000000..85c7d193 --- /dev/null +++ b/master/eoe_request.h @@ -0,0 +1,77 @@ +/****************************************************************************** + * + * $Id$ + * + * Copyright (C) 2006-2014 Florian Pose, Ingenieurgemeinschaft IgH + * + * This file is part of the IgH EtherCAT Master. + * + * The IgH EtherCAT Master is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * The IgH EtherCAT Master is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with the IgH EtherCAT Master; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * --- + * + * The license mentioned above concerns the source code only. Using the + * EtherCAT technology and brand is only permitted in compliance with the + * industrial property and similar rights of Beckhoff Automation GmbH. + * + *****************************************************************************/ + +/** + \file + EtherCAT EoE request structure. +*/ + +/*****************************************************************************/ + +#ifndef __EC_EOE_REQUEST_H__ +#define __EC_EOE_REQUEST_H__ + +#include +#include // ETH_ALEN + +#include "globals.h" + +/*****************************************************************************/ + +/** Ethernet-over-EtherCAT set IP parameter request. + */ +typedef struct { + struct list_head list; /**< List item. */ + ec_internal_request_state_t state; /**< Request state. */ + unsigned long jiffies_sent; /**< Jiffies, when the request was sent. */ + + uint8_t mac_address_included; + uint8_t ip_address_included; + uint8_t subnet_mask_included; + uint8_t gateway_included; + uint8_t dns_included; + uint8_t name_included; + + unsigned char mac_address[ETH_ALEN]; + uint32_t ip_address; + uint32_t subnet_mask; + uint32_t gateway; + uint32_t dns; + char name[EC_MAX_HOSTNAME_SIZE]; + + uint16_t result; +} ec_eoe_request_t; + +/*****************************************************************************/ + +void ec_eoe_request_init(ec_eoe_request_t *); + +/*****************************************************************************/ + +#endif diff --git a/master/fsm_eoe.c b/master/fsm_eoe.c new file mode 100644 index 00000000..285cbd05 --- /dev/null +++ b/master/fsm_eoe.c @@ -0,0 +1,485 @@ +/****************************************************************************** + * + * $Id$ + * + * Copyright (C) 2006-2014 Florian Pose, Ingenieurgemeinschaft IgH + * + * This file is part of the IgH EtherCAT Master. + * + * The IgH EtherCAT Master is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * The IgH EtherCAT Master is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with the IgH EtherCAT Master; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * --- + * + * The license mentioned above concerns the source code only. Using the + * EtherCAT technology and brand is only permitted in compliance with the + * industrial property and similar rights of Beckhoff Automation GmbH. + * + *****************************************************************************/ + +/** + \file + EtherCAT EoE state machines. +*/ + +/*****************************************************************************/ + +#include "globals.h" +#include "master.h" +#include "mailbox.h" +#include "fsm_eoe.h" + +/*****************************************************************************/ + +/** Maximum time to wait for a set IP parameter response. + */ +#define EC_EOE_RESPONSE_TIMEOUT 3000 // [ms] + +/*****************************************************************************/ + +void ec_fsm_eoe_set_ip_start(ec_fsm_eoe_t *, ec_datagram_t *); +void ec_fsm_eoe_set_ip_request(ec_fsm_eoe_t *, ec_datagram_t *); +void ec_fsm_eoe_set_ip_check(ec_fsm_eoe_t *, ec_datagram_t *); +void ec_fsm_eoe_set_ip_response(ec_fsm_eoe_t *, ec_datagram_t *); + +void ec_fsm_eoe_end(ec_fsm_eoe_t *, ec_datagram_t *); +void ec_fsm_eoe_error(ec_fsm_eoe_t *, ec_datagram_t *); + +/*****************************************************************************/ + +/** Constructor. + */ +void ec_fsm_eoe_init( + ec_fsm_eoe_t *fsm /**< finite state machine */ + ) +{ + fsm->slave = NULL; + fsm->retries = 0; + fsm->state = NULL; + fsm->datagram = NULL; + fsm->jiffies_start = 0; + fsm->request = NULL; +} + +/*****************************************************************************/ + +/** Destructor. + */ +void ec_fsm_eoe_clear( + ec_fsm_eoe_t *fsm /**< finite state machine */ + ) +{ +} + +/*****************************************************************************/ + +/** Starts to set the EoE IP partameters of a slave. + */ +void ec_fsm_eoe_set_ip_param( + ec_fsm_eoe_t *fsm, /**< State machine. */ + ec_slave_t *slave, /**< EtherCAT slave. */ + ec_eoe_request_t *request /**< EoE request. */ + ) +{ + fsm->slave = slave; + fsm->request = request; + fsm->state = ec_fsm_eoe_set_ip_start; +} + +/*****************************************************************************/ + +/** Executes the current state of the state machine. + * + * \return 1 if the datagram was used, else 0. + */ +int ec_fsm_eoe_exec( + ec_fsm_eoe_t *fsm, /**< finite state machine */ + ec_datagram_t *datagram /**< Datagram to use. */ + ) +{ + int datagram_used = 0; + + if (fsm->datagram && + (fsm->datagram->state == EC_DATAGRAM_INIT || + fsm->datagram->state == EC_DATAGRAM_QUEUED || + fsm->datagram->state == EC_DATAGRAM_SENT)) { + // datagram not received yet + return datagram_used; + } + + fsm->state(fsm, datagram); + + datagram_used = + fsm->state != ec_fsm_eoe_end && fsm->state != ec_fsm_eoe_error; + + if (datagram_used) { + fsm->datagram = datagram; + } else { + fsm->datagram = NULL; + } + + return datagram_used; +} + +/*****************************************************************************/ + +/** Returns, if the state machine terminated with success. + * + * \return non-zero if successful. + */ +int ec_fsm_eoe_success(const ec_fsm_eoe_t *fsm /**< Finite state machine */) +{ + return fsm->state == ec_fsm_eoe_end; +} + +/****************************************************************************** + * EoE set IP parameter state machine + *****************************************************************************/ + +/** Prepare a set IP parameters operation. + * + * \return 0 on success, otherwise a negative error code. + */ +int ec_fsm_eoe_prepare_set( + ec_fsm_eoe_t *fsm, /**< finite state machine */ + ec_datagram_t *datagram /**< Datagram to use. */ + ) +{ + uint8_t *data, *cur; + ec_slave_t *slave = fsm->slave; + ec_master_t *master = slave->master; + ec_eoe_request_t *req = fsm->request; + size_t size = 8; + + if (req->mac_address_included) { + size += ETH_ALEN; + } + + if (req->ip_address_included) { + size += 4; + } + + if (req->subnet_mask_included) { + size += 4; + } + + if (req->gateway_included) { + size += 4; + } + + if (req->dns_included) { + size += 4; + } + + if (req->name_included) { + size += EC_MAX_HOSTNAME_SIZE; + } + + data = ec_slave_mbox_prepare_send(slave, datagram, EC_MBOX_TYPE_EOE, + size); + if (IS_ERR(data)) { + return PTR_ERR(data); + } + + EC_WRITE_U8(data, EC_EOE_FRAMETYPE_SET_IP_REQ); // Set IP parameter req. + EC_WRITE_U8(data + 1, 0x01); // last fragment, no timestamps + EC_WRITE_U16(data + 2, 0x0000); // fragment no., offset, frame no. + + EC_WRITE_U32(data + 4, + ((req->mac_address_included != 0) << 0) | + ((req->ip_address_included != 0) << 1) | + ((req->subnet_mask_included != 0) << 2) | + ((req->gateway_included != 0) << 3) | + ((req->dns_included != 0) << 4) | + ((req->name_included != 0) << 5) + ); + + cur = data + 8; + + if (req->mac_address_included) { + memcpy(cur, req->mac_address, ETH_ALEN); + cur += ETH_ALEN; + } + + if (req->ip_address_included) { + memcpy(cur, &req->ip_address, 4); + cur += 4; + } + + if (req->subnet_mask_included) { + memcpy(cur, &req->subnet_mask, 4); + cur += 4; + } + + if (req->gateway_included) { + memcpy(cur, &req->gateway, 4); + cur += 4; + } + + if (req->dns_included) { + memcpy(cur, &req->dns, 4); + cur += 4; + } + + if (req->name_included) { + memcpy(cur, req->name, EC_MAX_HOSTNAME_SIZE); + cur += EC_MAX_HOSTNAME_SIZE; + } + + if (master->debug_level) { + EC_SLAVE_DBG(slave, 0, "Set IP parameter request:\n"); + ec_print_data(data, cur - data); + } + + fsm->request->jiffies_sent = jiffies; + + return 0; +} + +/*****************************************************************************/ + +/** EoE state: SET IP START. + */ +void ec_fsm_eoe_set_ip_start( + ec_fsm_eoe_t *fsm, /**< finite state machine */ + ec_datagram_t *datagram /**< Datagram to use. */ + ) +{ + ec_slave_t *slave = fsm->slave; + + EC_SLAVE_DBG(slave, 1, "Setting IP parameters.\n"); + + if (!(slave->sii.mailbox_protocols & EC_MBOX_EOE)) { + EC_SLAVE_ERR(slave, "Slave does not support EoE!\n"); + fsm->state = ec_fsm_eoe_error; + return; + } + + if (ec_fsm_eoe_prepare_set(fsm, datagram)) { + fsm->state = ec_fsm_eoe_error; + return; + } + + fsm->retries = EC_FSM_RETRIES; + fsm->state = ec_fsm_eoe_set_ip_request; +} + +/*****************************************************************************/ + +/** EoE state: SET IP REQUEST. + */ +void ec_fsm_eoe_set_ip_request( + ec_fsm_eoe_t *fsm, /**< finite state machine */ + ec_datagram_t *datagram /**< Datagram to use. */ + ) +{ + ec_slave_t *slave = fsm->slave; + + if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) { + if (ec_fsm_eoe_prepare_set(fsm, datagram)) { + fsm->state = ec_fsm_eoe_error; + } + return; + } + + if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) { + fsm->state = ec_fsm_eoe_error; + EC_SLAVE_ERR(slave, "Failed to receive EoE set IP parameter" + " request: "); + ec_datagram_print_state(fsm->datagram); + return; + } + + if (fsm->datagram->working_counter != 1) { + unsigned long diff_ms = + (jiffies - fsm->request->jiffies_sent) * 1000 / HZ; + + if (!fsm->datagram->working_counter) { + if (diff_ms < EC_EOE_RESPONSE_TIMEOUT) { + // no response; send request datagram again + if (ec_fsm_eoe_prepare_set(fsm, datagram)) { + fsm->state = ec_fsm_eoe_error; + } + return; + } + } + fsm->state = ec_fsm_eoe_error; + EC_SLAVE_ERR(slave, "Reception of EoE set IP parameter request" + " failed after %lu ms: ", diff_ms); + ec_datagram_print_wc_error(fsm->datagram); + return; + } + + fsm->jiffies_start = fsm->datagram->jiffies_sent; + ec_slave_mbox_prepare_check(slave, datagram); // can not fail. + fsm->retries = EC_FSM_RETRIES; + fsm->state = ec_fsm_eoe_set_ip_check; +} + +/*****************************************************************************/ + +/** EoE state: SET IP CHECK. + */ +void ec_fsm_eoe_set_ip_check( + ec_fsm_eoe_t *fsm, /**< finite state machine */ + ec_datagram_t *datagram /**< Datagram to use. */ + ) +{ + ec_slave_t *slave = fsm->slave; + + if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) { + ec_slave_mbox_prepare_check(slave, datagram); // can not fail. + return; + } + + if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) { + fsm->state = ec_fsm_eoe_error; + EC_SLAVE_ERR(slave, "Failed to receive EoE mailbox check datagram: "); + ec_datagram_print_state(fsm->datagram); + return; + } + + if (fsm->datagram->working_counter != 1) { + fsm->state = ec_fsm_eoe_error; + EC_SLAVE_ERR(slave, "Reception of EoE mailbox check" + " datagram failed: "); + ec_datagram_print_wc_error(fsm->datagram); + return; + } + + if (!ec_slave_mbox_check(fsm->datagram)) { + unsigned long diff_ms = + (fsm->datagram->jiffies_received - fsm->jiffies_start) * + 1000 / HZ; + if (diff_ms >= EC_EOE_RESPONSE_TIMEOUT) { + fsm->state = ec_fsm_eoe_error; + EC_SLAVE_ERR(slave, "Timeout after %lu ms while waiting for" + " set IP parameter response.\n", diff_ms); + return; + } + + ec_slave_mbox_prepare_check(slave, datagram); // can not fail. + fsm->retries = EC_FSM_RETRIES; + return; + } + + // fetch response + ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail. + fsm->retries = EC_FSM_RETRIES; + fsm->state = ec_fsm_eoe_set_ip_response; +} + +/*****************************************************************************/ + +/** EoE state: SET IP RESPONSE. + */ +void ec_fsm_eoe_set_ip_response( + ec_fsm_eoe_t *fsm, /**< finite state machine */ + ec_datagram_t *datagram /**< Datagram to use. */ + ) +{ + ec_slave_t *slave = fsm->slave; + ec_master_t *master = slave->master; + uint8_t *data, mbox_prot, frame_type; + size_t rec_size; + ec_eoe_request_t *req = fsm->request; + + if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) { + ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail. + return; + } + + if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) { + fsm->state = ec_fsm_eoe_error; + EC_SLAVE_ERR(slave, "Failed to receive EoE read response datagram: "); + ec_datagram_print_state(fsm->datagram); + return; + } + + if (fsm->datagram->working_counter != 1) { + fsm->state = ec_fsm_eoe_error; + EC_SLAVE_ERR(slave, "Reception of EoE read response failed: "); + ec_datagram_print_wc_error(fsm->datagram); + return; + } + + data = ec_slave_mbox_fetch(slave, fsm->datagram, &mbox_prot, &rec_size); + if (IS_ERR(data)) { + fsm->state = ec_fsm_eoe_error; + return; + } + + if (master->debug_level) { + EC_SLAVE_DBG(slave, 0, "Set IP parameter response:\n"); + ec_print_data(data, rec_size); + } + + if (mbox_prot != EC_MBOX_TYPE_EOE) { + fsm->state = ec_fsm_eoe_error; + EC_SLAVE_ERR(slave, "Received mailbox protocol 0x%02X as response.\n", + mbox_prot); + return; + } + + if (rec_size < 4) { + fsm->state = ec_fsm_eoe_error; + EC_SLAVE_ERR(slave, "Received currupted EoE set IP parameter response" + " (%zu bytes)!\n", rec_size); + ec_print_data(data, rec_size); + return; + } + + frame_type = EC_READ_U8(data) & 0x0f; + + if (frame_type != EC_EOE_FRAMETYPE_SET_IP_RES) { + EC_SLAVE_ERR(slave, "Received no set IP parameter response" + " (frame type %x).\n", frame_type); + ec_print_data(data, rec_size); + fsm->state = ec_fsm_eoe_error; + return; + } + + req->result = EC_READ_U16(data + 2); + + if (req->result) { + fsm->state = ec_fsm_eoe_error; + EC_SLAVE_DBG(slave, 1, "EoE set IP parameters failed with result code" + " 0x%04X.\n", req->result); + } else { + fsm->state = ec_fsm_eoe_end; // success + } +} + +/*****************************************************************************/ + +/** State: ERROR. + */ +void ec_fsm_eoe_error( + ec_fsm_eoe_t *fsm, /**< finite state machine */ + ec_datagram_t *datagram /**< Datagram to use. */ + ) +{ +} + +/*****************************************************************************/ + +/** State: END. + */ +void ec_fsm_eoe_end( + ec_fsm_eoe_t *fsm, /**< finite state machine */ + ec_datagram_t *datagram /**< Datagram to use. */ + ) +{ +} + +/*****************************************************************************/ diff --git a/master/fsm_eoe.h b/master/fsm_eoe.h new file mode 100644 index 00000000..949b0798 --- /dev/null +++ b/master/fsm_eoe.h @@ -0,0 +1,74 @@ +/***************************************************************************** + * + * $Id$ + * + * Copyright (C) 2006-2014 Florian Pose, Ingenieurgemeinschaft IgH + * + * This file is part of the IgH EtherCAT Master. + * + * The IgH EtherCAT Master is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * The IgH EtherCAT Master is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with the IgH EtherCAT Master; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * --- + * + * The license mentioned above concerns the source code only. Using the + * EtherCAT technology and brand is only permitted in compliance with the + * industrial property and similar rights of Beckhoff Automation GmbH. + * + ****************************************************************************/ + +/** + \file + EtherCAT EoE set IP parameter state machines. +*/ + +/****************************************************************************/ + +#ifndef __EC_FSM_EOE_H__ +#define __EC_FSM_EOE_H__ + +#include "globals.h" +#include "datagram.h" +#include "slave.h" +#include "eoe_request.h" + +/****************************************************************************/ + +typedef struct ec_fsm_eoe ec_fsm_eoe_t; /**< \see ec_fsm_eoe */ + +/** Finite state machines for the Ethernet over EtherCAT protocol. + */ +struct ec_fsm_eoe { + ec_slave_t *slave; /**< slave the FSM runs on */ + unsigned int retries; /**< retries upon datagram timeout */ + + void (*state)(ec_fsm_eoe_t *, ec_datagram_t *); /**< EoE state function */ + ec_datagram_t *datagram; /**< Datagram used in the previous step. */ + unsigned long jiffies_start; /**< Timestamp. */ + ec_eoe_request_t *request; /**< EoE request */ +}; + +/****************************************************************************/ + +void ec_fsm_eoe_init(ec_fsm_eoe_t *); +void ec_fsm_eoe_clear(ec_fsm_eoe_t *); + +void ec_fsm_eoe_set_ip_param(ec_fsm_eoe_t *, ec_slave_t *, + ec_eoe_request_t *); + +int ec_fsm_eoe_exec(ec_fsm_eoe_t *, ec_datagram_t *); +int ec_fsm_eoe_success(const ec_fsm_eoe_t *); + +/****************************************************************************/ + +#endif diff --git a/master/fsm_slave.c b/master/fsm_slave.c index 0ddb76f7..67315cf2 100644 --- a/master/fsm_slave.c +++ b/master/fsm_slave.c @@ -52,6 +52,8 @@ 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 *); +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 @@ void ec_fsm_slave_init( 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 @@ void ec_fsm_slave_clear( 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 @@ void ec_fsm_slave_state_ready( 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 @@ 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) { @@ -248,7 +263,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; @@ -342,7 +357,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! @@ -444,7 +459,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; @@ -521,7 +536,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) { @@ -580,3 +595,85 @@ void ec_fsm_slave_state_soe_request( } /*****************************************************************************/ + +/** Check for pending EoE IP parameter requests and process one. + * + * \return non-zero, if a request is processed. + */ +int ec_fsm_slave_action_process_eoe( + ec_fsm_slave_t *fsm, /**< Slave state machine. */ + ec_datagram_t *datagram /**< Datagram to use. */ + ) +{ + ec_slave_t *slave = fsm->slave; + ec_eoe_request_t *request; + + if (list_empty(&slave->eoe_requests)) { + return 0; + } + + // take the first request to be processed + request = list_entry(slave->eoe_requests.next, ec_eoe_request_t, list); + list_del_init(&request->list); // dequeue + + if (slave->current_state & EC_SLAVE_STATE_ACK_ERR) { + EC_SLAVE_WARN(slave, "Aborting EoE request," + " slave has error flag set.\n"); + request->state = EC_INT_REQUEST_FAILURE; + wake_up_all(&slave->master->request_queue); + fsm->state = ec_fsm_slave_state_idle; + return 0; + } + + if (slave->current_state == EC_SLAVE_STATE_INIT) { + EC_SLAVE_WARN(slave, "Aborting EoE request, slave is in INIT.\n"); + request->state = EC_INT_REQUEST_FAILURE; + wake_up_all(&slave->master->request_queue); + fsm->state = ec_fsm_slave_state_idle; + return 0; + } + + fsm->eoe_request = request; + request->state = EC_INT_REQUEST_BUSY; + + // Found pending request. Execute it! + EC_SLAVE_DBG(slave, 1, "Processing EoE request...\n"); + + // Start EoE command + fsm->state = ec_fsm_slave_state_eoe_request; + ec_fsm_eoe_set_ip_param(&fsm->fsm_eoe, slave, request); + ec_fsm_eoe_exec(&fsm->fsm_eoe, datagram); // execute immediately + return 1; +} + +/*****************************************************************************/ + +/** Slave state: EOE_REQUEST. + */ +void ec_fsm_slave_state_eoe_request( + ec_fsm_slave_t *fsm, /**< Slave state machine. */ + ec_datagram_t *datagram /**< Datagram to use. */ + ) +{ + ec_slave_t *slave = fsm->slave; + ec_eoe_request_t *req = fsm->eoe_request; + + if (ec_fsm_eoe_exec(&fsm->fsm_eoe, datagram)) { + return; + } + + if (ec_fsm_eoe_success(&fsm->fsm_eoe)) { + req->state = EC_INT_REQUEST_SUCCESS; + EC_SLAVE_DBG(slave, 1, "Finished EoE request.\n"); + } + else { + req->state = EC_INT_REQUEST_FAILURE; + EC_SLAVE_ERR(slave, "Failed to process EoE request.\n"); + } + + wake_up_all(&slave->master->request_queue); + fsm->eoe_request = NULL; + fsm->state = ec_fsm_slave_state_ready; +} + +/*****************************************************************************/ diff --git a/master/fsm_slave.h b/master/fsm_slave.h index b511a668..f051d5bb 100644 --- a/master/fsm_slave.h +++ b/master/fsm_slave.h @@ -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 @@ 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. */ + ec_eoe_request_t *eoe_request; /**< SoE request to process. */ ec_fsm_coe_t fsm_coe; /**< CoE state machine. */ ec_fsm_foe_t fsm_foe; /**< FoE state machine. */ ec_fsm_soe_t fsm_soe; /**< SoE state machine. */ + ec_fsm_eoe_t fsm_eoe; /**< EoE state machine. */ }; /*****************************************************************************/ diff --git a/master/globals.h b/master/globals.h index 69f313bf..0e757368 100644 --- a/master/globals.h +++ b/master/globals.h @@ -103,6 +103,12 @@ **/ #define EC_DATAGRAM_NAME_SIZE 20 +/** Maximum hostname size. + * + * Used inside the EoE set IP parameter request. + */ +#define EC_MAX_HOSTNAME_SIZE 32 + /** Slave state mask. * * Apply this mask to a slave state byte to get the slave state without diff --git a/master/ioctl.c b/master/ioctl.c index ac87de51..7c454c74 100644 --- a/master/ioctl.c +++ b/master/ioctl.c @@ -1617,6 +1617,89 @@ static ATTRIBUTES int ec_ioctl_eoe_handler( /*****************************************************************************/ +/** 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. @@ -4369,6 +4452,13 @@ long EC_IOCTL( case EC_IOCTL_SLAVE_SOE_READ: ret = ec_ioctl_slave_soe_read(master, arg); break; + case EC_IOCTL_SLAVE_EOE_IP_PARAM: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_slave_eoe_ip_param(master, arg); + break; case EC_IOCTL_SLAVE_SOE_WRITE: if (!ctx->writable) { ret = -EPERM; diff --git a/master/ioctl.h b/master/ioctl.h index 3f750cc3..539d1f66 100644 --- a/master/ioctl.h +++ b/master/ioctl.h @@ -47,7 +47,7 @@ * * Increment this when changing the ioctl interface! */ -#define EC_IOCTL_VERSION_MAGIC 32 +#define EC_IOCTL_VERSION_MAGIC 33 // Command-line tool #define EC_IOCTL_MODULE EC_IOR(0x00, ec_ioctl_module_t) @@ -74,78 +74,81 @@ #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_REG_REQUEST EC_IOWR(0x40, ec_ioctl_reg_request_t) -#define EC_IOCTL_SC_VOE EC_IOWR(0x41, ec_ioctl_voe_t) -#define EC_IOCTL_SC_STATE EC_IOWR(0x42, ec_ioctl_sc_state_t) -#define EC_IOCTL_SC_IDN EC_IOW(0x43, ec_ioctl_sc_idn_t) -#define EC_IOCTL_SC_FLAG EC_IOW(0x44, ec_ioctl_sc_flag_t) -#define EC_IOCTL_DOMAIN_SIZE EC_IO(0x45) -#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x46) -#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x47) -#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x48) -#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x49, ec_ioctl_domain_state_t) -#define EC_IOCTL_SDO_REQUEST_INDEX EC_IOWR(0x4a, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x4b, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x4c, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x4d, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x4e, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x4f, ec_ioctl_sdo_request_t) -#define EC_IOCTL_REG_REQUEST_DATA EC_IOWR(0x50, ec_ioctl_reg_request_t) -#define EC_IOCTL_REG_REQUEST_STATE EC_IOWR(0x51, ec_ioctl_reg_request_t) -#define EC_IOCTL_REG_REQUEST_WRITE EC_IOWR(0x52, ec_ioctl_reg_request_t) -#define EC_IOCTL_REG_REQUEST_READ EC_IOWR(0x53, ec_ioctl_reg_request_t) -#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x54, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x55, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_READ EC_IOW(0x56, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x57, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_WRITE EC_IOWR(0x58, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_EXEC EC_IOWR(0x59, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_DATA EC_IOWR(0x5a, ec_ioctl_voe_t) -#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x5b, 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_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_REG_REQUEST_DATA EC_IOWR(0x51, ec_ioctl_reg_request_t) +#define EC_IOCTL_REG_REQUEST_STATE EC_IOWR(0x52, ec_ioctl_reg_request_t) +#define EC_IOCTL_REG_REQUEST_WRITE EC_IOWR(0x53, ec_ioctl_reg_request_t) +#define EC_IOCTL_REG_REQUEST_READ EC_IOWR(0x54, ec_ioctl_reg_request_t) +#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x55, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x56, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_READ EC_IOW(0x57, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x58, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_WRITE EC_IOWR(0x59, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_EXEC EC_IOWR(0x5a, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_DATA EC_IOWR(0x5b, ec_ioctl_voe_t) +#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x5c, size_t) /*****************************************************************************/ @@ -600,6 +603,37 @@ typedef struct { /*****************************************************************************/ +#define EC_ETH_ALEN 6 +#ifdef ETH_ALEN +#if ETH_ALEN != EC_ETH_ALEN +#error Ethernet address length mismatch +#endif +#endif + +typedef struct { + // input + uint16_t slave_position; + + uint8_t mac_address_included; + uint8_t ip_address_included; + uint8_t subnet_mask_included; + uint8_t gateway_included; + uint8_t dns_included; + uint8_t name_included; + + unsigned char mac_address[EC_ETH_ALEN]; + uint32_t ip_address; + uint32_t subnet_mask; + uint32_t gateway; + uint32_t dns; + char name[EC_MAX_HOSTNAME_SIZE]; + + // output + uint16_t result; +} ec_ioctl_slave_eoe_ip_t; + +/*****************************************************************************/ + typedef struct { // outputs void *process_data; diff --git a/master/slave.c b/master/slave.c index c081fe3f..24143491 100644 --- a/master/slave.c +++ b/master/slave.c @@ -155,6 +155,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); @@ -211,6 +212,15 @@ void ec_slave_clear(ec_slave_t *slave /**< EtherCAT slave */) request->state = EC_INT_REQUEST_FAILURE; } + while (!list_empty(&slave->eoe_requests)) { + ec_eoe_request_t *request = + list_entry(slave->eoe_requests.next, ec_eoe_request_t, list); + list_del_init(&request->list); // dequeue + EC_SLAVE_WARN(slave, "Discarding EoE request," + " slave about to be deleted.\n"); + request->state = EC_INT_REQUEST_FAILURE; + } + wake_up_all(&slave->master->request_queue); if (slave->config) { diff --git a/master/slave.h b/master/slave.h index b71d57e2..f5114e34 100644 --- a/master/slave.h +++ b/master/slave.h @@ -228,8 +228,9 @@ struct ec_slave struct list_head sdo_requests; /**< SDO access requests. */ struct list_head reg_requests; /**< Register access requests. */ - struct list_head foe_requests; /**< FoE write requests. */ - struct list_head soe_requests; /**< SoE write requests. */ + struct list_head foe_requests; /**< FoE requests. */ + struct list_head soe_requests; /**< SoE requests. */ + struct list_head eoe_requests; /**< EoE set IP parameter requests. */ ec_fsm_slave_t fsm; /**< Slave state machine. */ }; diff --git a/tool/CommandIp.cpp b/tool/CommandIp.cpp new file mode 100644 index 00000000..21314fce --- /dev/null +++ b/tool/CommandIp.cpp @@ -0,0 +1,258 @@ +/***************************************************************************** + * + * $Id$ + * + * Copyright (C) 2006-2014 Florian Pose, Ingenieurgemeinschaft IgH + * + * This file is part of the IgH EtherCAT Master. + * + * The IgH EtherCAT Master is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * The IgH EtherCAT Master is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with the IgH EtherCAT Master; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * --- + * + * The license mentioned above concerns the source code only. Using the + * EtherCAT technology and brand is only permitted in compliance with the + * industrial property and similar rights of Beckhoff Automation GmbH. + * + * vim: expandtab + * + ****************************************************************************/ + +#include +#include +#include + +#include +#include +using namespace std; + +#include "CommandIp.h" +#include "MasterDevice.h" + +/*****************************************************************************/ + +CommandIp::CommandIp(): + Command("ip", "Set EoE IP parameters.") +{ +} + +/*****************************************************************************/ + +string CommandIp::helpString(const string &binaryBaseName) const +{ + stringstream str; + + str << binaryBaseName << " " << getName() << " [OPTIONS] " << endl + << endl + << getBriefDescription() << endl + << endl + << "This command requires a single slave to be selected." << endl + << endl + << "IP parameters can be appended as argument pairs:" << endl + << endl + << " addr [/prefix] IP address (optionally with" << endl + << " decimal subnet prefix)" << endl + << " link Link-layer address (may contain" << endl + << " colons or hyphens)" << endl + << " default Default gateway" << endl + << " dns DNS server" << endl + << " name Host name (max. 32 byte)" << endl + << endl + << "IPv4 adresses can be given either in dot notation or as" << endl + << "hostnames, which will be automatically resolved." << endl + << endl + << "Command-specific options:" << endl + << " --alias -a " << endl + << " --position -p Slave selection. See the help of" << endl + << " the 'slaves' command." << endl + << endl + << numericInfo(); + + return str.str(); +} + +/****************************************************************************/ + +void CommandIp::execute(const StringVector &args) +{ + if (args.size() <= 0) { + return; + } + + if (args.size() % 2) { + stringstream err; + err << "'" << getName() << "' needs an even number of arguments!"; + throwInvalidUsageException(err); + } + + ec_ioctl_slave_eoe_ip_t io = {}; + + for (unsigned int argIdx = 0; argIdx < args.size(); argIdx += 2) { + string arg = args[argIdx]; + string val = args[argIdx + 1]; + std::transform(arg.begin(), arg.end(), arg.begin(), ::tolower); + + if (arg == "link") { + parseMac(io.mac_address, val); + io.mac_address_included = 1; + } + else if (arg == "addr") { + parseIpv4Prefix(&io, val); + io.ip_address_included = 1; + } + else if (arg == "default") { + resolveIpv4(&io.gateway, val); + io.gateway_included = 1; + } + else if (arg == "dns") { + resolveIpv4(&io.dns, val); + io.dns_included = 1; + } + else if (arg == "name") { + if (val.size() > EC_MAX_HOSTNAME_SIZE - 1) { + stringstream err; + err << "Name too long!"; + throwInvalidUsageException(err); + } + unsigned int i; + for (i = 0; i < val.size(); i++) { + io.name[i] = val[i]; + } + io.name[i] = 0; + io.name_included = 1; + } + else { + stringstream err; + err << "Unknown argument '" << args[argIdx] << "'!"; + throwInvalidUsageException(err); + } + } + + MasterDevice m(getSingleMasterIndex()); + m.open(MasterDevice::ReadWrite); + SlaveList slaves = selectedSlaves(m); + if (slaves.size() != 1) { + throwSingleSlaveRequired(slaves.size()); + } + io.slave_position = slaves.front().position; + + // execute actual request + try { + m.setIpParam(&io); + } catch (MasterDeviceException &e) { + throw e; + } +} + +/*****************************************************************************/ + +void CommandIp::parseMac(unsigned char mac[EC_ETH_ALEN], const string &str) +{ + unsigned int pos = 0; + + for (unsigned int i = 0; i < EC_ETH_ALEN; i++) { + if (pos + 2 > str.size()) { + stringstream err; + err << "Incomplete MAC address!"; + throwInvalidUsageException(err); + } + + string byteStr = str.substr(pos, 2); + pos += 2; + + stringstream s; + s << byteStr; + unsigned int byteValue; + s >> hex >> byteValue; + if (s.fail() || !s.eof() || byteValue > 0xff) { + stringstream err; + err << "Invalid MAC address!"; + throwInvalidUsageException(err); + } + mac[i] = byteValue; + + while (pos < str.size() && (str[pos] == ':' || str[pos] == '-')) { + pos++; + } + } +} + +/*****************************************************************************/ + +void CommandIp::parseIpv4Prefix(ec_ioctl_slave_eoe_ip_t *io, + const string &str) +{ + size_t pos = str.find('/'); + string host; + + io->subnet_mask_included = pos != string::npos; + + if (pos == string::npos) { // no prefix found + host = str; + } + else { + host = str.substr(0, pos); + string prefixStr = str.substr(pos + 1, string::npos); + stringstream s; + s << prefixStr; + unsigned int prefix; + s >> prefix; + if (s.fail() || !s.eof() || prefix > 32) { + stringstream err; + err << "Invalid prefix '" << prefixStr << "'!"; + throwInvalidUsageException(err); + } + uint32_t mask = 0; + for (unsigned int bit = 0; bit < prefix; bit++) { + mask |= (1 << (31 - bit)); + } + io->subnet_mask = htonl(mask); + } + + resolveIpv4(&io->ip_address, host); +} + +/*****************************************************************************/ + +void CommandIp::resolveIpv4(uint32_t *addr, const string &str) +{ + struct addrinfo hints = {}; + struct addrinfo *res; + + hints.ai_family = AF_INET; // only IPv4 + + int ret = getaddrinfo(str.c_str(), NULL, &hints, &res); + if (ret) { + stringstream err; + err << "Lookup of '" << str << "' failed: " + << gai_strerror(ret) << endl; + throwCommandException(err.str()); + } + + if (!res) { // returned list is empty + stringstream err; + err << "Lookup of '" << str << "' failed." << endl; + throwCommandException(err.str()); + } + + sockaddr_in *sin = (sockaddr_in *) res->ai_addr; + for (unsigned int i = 0; i < 4; i++) { + ((unsigned char *) addr)[i] = + ((unsigned char *) &sin->sin_addr.s_addr)[i]; + } + + freeaddrinfo(res); +} + +/****************************************************************************/ diff --git a/tool/CommandIp.h b/tool/CommandIp.h new file mode 100644 index 00000000..ff8d7f1a --- /dev/null +++ b/tool/CommandIp.h @@ -0,0 +1,55 @@ +/***************************************************************************** + * + * $Id$ + * + * Copyright (C) 2006-2014 Florian Pose, Ingenieurgemeinschaft IgH + * + * This file is part of the IgH EtherCAT Master. + * + * The IgH EtherCAT Master is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * The IgH EtherCAT Master is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with the IgH EtherCAT Master; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * --- + * + * The license mentioned above concerns the source code only. Using the + * EtherCAT technology and brand is only permitted in compliance with the + * industrial property and similar rights of Beckhoff Automation GmbH. + * + ****************************************************************************/ + +#ifndef __COMMANDIP_H__ +#define __COMMANDIP_H__ + +#include "Command.h" + +/****************************************************************************/ + +class CommandIp: + public Command +{ + public: + CommandIp(); + + string helpString(const string &) const; + void execute(const StringVector &); + + protected: + void parseMac(unsigned char [6], const string &); + void parseIpv4Prefix(ec_ioctl_slave_eoe_ip_t *, + const string &); + void resolveIpv4(uint32_t *, const string &); +}; + +/****************************************************************************/ + +#endif diff --git a/tool/Makefile.am b/tool/Makefile.am index e13dbf11..5961aabf 100644 --- a/tool/Makefile.am +++ b/tool/Makefile.am @@ -49,6 +49,7 @@ ethercat_SOURCES = \ CommandFoeRead.cpp \ CommandFoeWrite.cpp \ CommandGraph.cpp \ + CommandIp.cpp \ CommandMaster.cpp \ CommandPdos.cpp \ CommandRegRead.cpp \ @@ -92,6 +93,7 @@ noinst_HEADERS = \ CommandFoeRead.h \ CommandFoeWrite.h \ CommandGraph.h \ + CommandIp.h \ CommandMaster.h \ CommandPdos.h \ CommandRegRead.h \ diff --git a/tool/MasterDevice.cpp b/tool/MasterDevice.cpp index f32ef1ad..4238affa 100644 --- a/tool/MasterDevice.cpp +++ b/tool/MasterDevice.cpp @@ -607,4 +607,19 @@ void MasterDevice::writeSoe(ec_ioctl_slave_soe_write_t *data) } } +/****************************************************************************/ + +void MasterDevice::setIpParam(ec_ioctl_slave_eoe_ip_t *data) +{ + if (ioctl(fd, EC_IOCTL_SLAVE_EOE_IP_PARAM, data) < 0) { + if (errno == EIO && data->result) { + throw MasterDeviceEoeException(data->result); + } else { + stringstream err; + err << "Failed to set IP parameters: " << strerror(errno); + throw MasterDeviceException(err); + } + } +} + /*****************************************************************************/ diff --git a/tool/MasterDevice.h b/tool/MasterDevice.h index 16db6ac7..c0d6c694 100644 --- a/tool/MasterDevice.h +++ b/tool/MasterDevice.h @@ -94,6 +94,23 @@ class MasterDeviceSoeException: /****************************************************************************/ +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: @@ -146,6 +163,7 @@ class MasterDevice #endif void readSoe(ec_ioctl_slave_soe_read_t *); void writeSoe(ec_ioctl_slave_soe_write_t *); + void setIpParam(ec_ioctl_slave_eoe_ip_t *); unsigned int getMasterCount() const {return masterCount;} diff --git a/tool/main.cpp b/tool/main.cpp index 42786918..dc756071 100644 --- a/tool/main.cpp +++ b/tool/main.cpp @@ -49,6 +49,7 @@ using namespace std; #include "CommandFoeRead.h" #include "CommandFoeWrite.h" #include "CommandGraph.h" +#include "CommandIp.h" #include "CommandMaster.h" #include "CommandPdos.h" #include "CommandRegRead.h" @@ -290,6 +291,7 @@ int main(int argc, char **argv) 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()); From 7b2084e270298a5664e783d675780a12b247dab9 Mon Sep 17 00:00:00 2001 From: Florian Pose Date: Tue, 3 May 2016 14:13:11 +0200 Subject: [PATCH 07/13] Fixed endianess of EoE parameters. --- master/fsm_eoe.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/master/fsm_eoe.c b/master/fsm_eoe.c index 285cbd05..4788ab67 100644 --- a/master/fsm_eoe.c +++ b/master/fsm_eoe.c @@ -212,22 +212,26 @@ int ec_fsm_eoe_prepare_set( } if (req->ip_address_included) { - memcpy(cur, &req->ip_address, 4); + uint32_t swapped = htonl(req->ip_address); + memcpy(cur, &swapped, 4); cur += 4; } if (req->subnet_mask_included) { - memcpy(cur, &req->subnet_mask, 4); + uint32_t swapped = htonl(req->subnet_mask); + memcpy(cur, &swapped, 4); cur += 4; } if (req->gateway_included) { - memcpy(cur, &req->gateway, 4); + uint32_t swapped = htonl(req->gateway); + memcpy(cur, &swapped, 4); cur += 4; } if (req->dns_included) { - memcpy(cur, &req->dns, 4); + uint32_t swapped = htonl(req->dns); + memcpy(cur, &swapped, 4); cur += 4; } From e6243c0907be378c8f3099f057793b00f2b3aa06 Mon Sep 17 00:00:00 2001 From: Florian Pose Date: Wed, 4 May 2016 10:29:55 +0200 Subject: [PATCH 08/13] Included "ethercat ip" command in documentation. --- documentation/Makefile | 1 + documentation/ethercat_doc.tex | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/documentation/Makefile b/documentation/Makefile index ff6971e2..3749a7e5 100644 --- a/documentation/Makefile +++ b/documentation/Makefile @@ -23,6 +23,7 @@ COMMANDS := \ foe_read \ foe_write \ graph \ + ip \ master \ pdos \ reg_read \ diff --git a/documentation/ethercat_doc.tex b/documentation/ethercat_doc.tex index 51205863..d6e5cf8c 100644 --- a/documentation/ethercat_doc.tex +++ b/documentation/ethercat_doc.tex @@ -2183,12 +2183,6 @@ 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} - -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. - %------------------------------------------------------------------------------ \section{CANopen over EtherCAT (CoE)} @@ -2444,6 +2438,12 @@ created, if the \lstinline+udev+ Package is installed. See %------------------------------------------------------------------------------ +\subsection{Setting Ethernet-over-EtherCAT IP Parameters} + +\lstinputlisting[basicstyle=\ttfamily\footnotesize]{external/ethercat_ip} + +%------------------------------------------------------------------------------ + \subsection{Master and Ethernet Devices} \lstinputlisting[basicstyle=\ttfamily\footnotesize]{external/ethercat_master} From 17fe43df94411f480b3e4c2b823da294990aee90 Mon Sep 17 00:00:00 2001 From: Florian Pose Date: Wed, 4 May 2016 11:17:20 +0200 Subject: [PATCH 09/13] EoE interface configuration hints. --- documentation/ethercat_doc.tex | 68 ++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/documentation/ethercat_doc.tex b/documentation/ethercat_doc.tex index d6e5cf8c..8e90fb5e 100644 --- a/documentation/ethercat_doc.tex +++ b/documentation/ethercat_doc.tex @@ -2058,6 +2058,9 @@ index and Y is the decimal alias address. \end{description} +For some hints on how to configure these virtual interfaces, see +\autoref{sec:eoe-config}. + Frames sent to these interfaces are forwarded to the associated slaves by the master. Frames, that are received by the slaves, are fetched by the master and forwarded to the virtual interfaces. @@ -2183,6 +2186,55 @@ 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}. +\subsection{EoE Interface Configuration} +\label{sec:eoe-config} + +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}). + %------------------------------------------------------------------------------ \section{CANopen over EtherCAT (CoE)} @@ -2439,6 +2491,22 @@ 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} From c04fe65fefb30a45d012ad23010d0e4455e4493c Mon Sep 17 00:00:00 2001 From: Bjarne von Horn Date: Wed, 20 Sep 2023 10:40:35 +0200 Subject: [PATCH 10/13] enable ip command in tool only if EC_EOE defined --- tool/Makefile.am | 10 ++++------ tool/MasterDevice.cpp | 2 ++ tool/MasterDevice.h | 2 ++ tool/main.cpp | 6 +++++- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/tool/Makefile.am b/tool/Makefile.am index 5961aabf..18a3acb6 100644 --- a/tool/Makefile.am +++ b/tool/Makefile.am @@ -49,7 +49,6 @@ ethercat_SOURCES = \ CommandFoeRead.cpp \ CommandFoeWrite.cpp \ CommandGraph.cpp \ - CommandIp.cpp \ CommandMaster.cpp \ CommandPdos.cpp \ CommandRegRead.cpp \ @@ -75,9 +74,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 = \ @@ -93,7 +92,6 @@ noinst_HEADERS = \ CommandFoeRead.h \ CommandFoeWrite.h \ CommandGraph.h \ - CommandIp.h \ CommandMaster.h \ CommandPdos.h \ CommandRegRead.h \ @@ -118,9 +116,9 @@ noinst_HEADERS = \ sii_crc.h if ENABLE_EOE -noinst_HEADERS += CommandEoe.h +noinst_HEADERS += CommandEoe.h CommandIp.h else -EXTRA_DIST += CommandEoe.h +EXTRA_DIST += CommandEoe.h CommandIp.h endif REV = `if test -s $(top_srcdir)/revision; then \ diff --git a/tool/MasterDevice.cpp b/tool/MasterDevice.cpp index 4238affa..d5faa524 100644 --- a/tool/MasterDevice.cpp +++ b/tool/MasterDevice.cpp @@ -609,6 +609,7 @@ 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) { @@ -621,5 +622,6 @@ void MasterDevice::setIpParam(ec_ioctl_slave_eoe_ip_t *data) } } } +#endif /*****************************************************************************/ diff --git a/tool/MasterDevice.h b/tool/MasterDevice.h index c0d6c694..0ad32420 100644 --- a/tool/MasterDevice.h +++ b/tool/MasterDevice.h @@ -94,6 +94,7 @@ class MasterDeviceSoeException: /****************************************************************************/ +#ifdef EC_EOE class MasterDeviceEoeException: public MasterDeviceException { @@ -108,6 +109,7 @@ class MasterDeviceEoeException: MasterDeviceException("EoE set IP parameter failed."), result(result) {}; }; +#endif /****************************************************************************/ diff --git a/tool/main.cpp b/tool/main.cpp index dc756071..0f6a0cb5 100644 --- a/tool/main.cpp +++ b/tool/main.cpp @@ -49,7 +49,9 @@ using namespace std; #include "CommandFoeRead.h" #include "CommandFoeWrite.h" #include "CommandGraph.h" -#include "CommandIp.h" +#ifdef EC_EOE +# include "CommandIp.h" +#endif #include "CommandMaster.h" #include "CommandPdos.h" #include "CommandRegRead.h" @@ -291,7 +293,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()); From 01c72a8865f8bc3b476518c6fc9a461e74002066 Mon Sep 17 00:00:00 2001 From: Bjarne von Horn Date: Wed, 20 Sep 2023 11:09:24 +0200 Subject: [PATCH 11/13] EoE for Set IP in master --- master/Kbuild.in | 4 +--- master/fsm_slave.c | 14 ++++++++++++++ master/fsm_slave.h | 8 ++++++++ master/ioctl.c | 4 ++++ master/slave.c | 2 ++ 5 files changed, 29 insertions(+), 3 deletions(-) diff --git a/master/Kbuild.in b/master/Kbuild.in index 14f6e300..ebadecce 100644 --- a/master/Kbuild.in +++ b/master/Kbuild.in @@ -40,13 +40,11 @@ ec_master-objs := \ datagram_pair.o \ device.o \ domain.o \ - eoe_request.o \ flag.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 \ @@ -76,7 +74,7 @@ ec_master-objs := \ voe_handler.o ifeq (@ENABLE_EOE@,1) -ec_master-objs += ethernet.o +ec_master-objs += eoe_request.o ethernet.o fsm_eoe.o endif ifeq (@ENABLE_DEBUG_IF@,1) diff --git a/master/fsm_slave.c b/master/fsm_slave.c index 67315cf2..11229d55 100644 --- a/master/fsm_slave.c +++ b/master/fsm_slave.c @@ -52,8 +52,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 /*****************************************************************************/ @@ -73,13 +75,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 } /*****************************************************************************/ @@ -112,16 +118,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 } /*****************************************************************************/ @@ -221,10 +231,12 @@ void ec_fsm_slave_state_ready( return; } +#ifdef EC_EOE // Check for pending EoE IP parameter requests if (ec_fsm_slave_action_process_eoe(fsm, datagram)) { return; } +#endif } /*****************************************************************************/ @@ -596,6 +608,7 @@ 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. @@ -677,3 +690,4 @@ void ec_fsm_slave_state_eoe_request( } /*****************************************************************************/ +#endif diff --git a/master/fsm_slave.h b/master/fsm_slave.h index f051d5bb..13fd9746 100644 --- a/master/fsm_slave.h +++ b/master/fsm_slave.h @@ -41,11 +41,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 /*****************************************************************************/ @@ -64,12 +68,16 @@ struct ec_fsm_slave { ec_foe_request_t *foe_request; /**< FoE request to process. */ off_t foe_index; /**< Index to FoE write request data. */ ec_soe_request_t *soe_request; /**< SoE request to process. */ +#ifdef EC_EOE ec_eoe_request_t *eoe_request; /**< SoE request to process. */ +#endif ec_fsm_coe_t fsm_coe; /**< CoE state machine. */ ec_fsm_foe_t fsm_foe; /**< FoE state machine. */ ec_fsm_soe_t fsm_soe; /**< SoE state machine. */ +#ifdef EC_EOE ec_fsm_eoe_t fsm_eoe; /**< EoE state machine. */ +#endif }; /*****************************************************************************/ diff --git a/master/ioctl.c b/master/ioctl.c index 7c454c74..3d0e1d81 100644 --- a/master/ioctl.c +++ b/master/ioctl.c @@ -1617,6 +1617,7 @@ static ATTRIBUTES int ec_ioctl_eoe_handler( /*****************************************************************************/ +#ifdef EC_EOE /** Request EoE IP parameter setting. * * \return Zero on success, otherwise a negative error code. @@ -1697,6 +1698,7 @@ static ATTRIBUTES int ec_ioctl_slave_eoe_ip_param( return req.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO; } +#endif /*****************************************************************************/ @@ -4452,6 +4454,7 @@ 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; @@ -4459,6 +4462,7 @@ long EC_IOCTL( } ret = ec_ioctl_slave_eoe_ip_param(master, arg); break; +#endif case EC_IOCTL_SLAVE_SOE_WRITE: if (!ctx->writable) { ret = -EPERM; diff --git a/master/slave.c b/master/slave.c index 24143491..406dd7c1 100644 --- a/master/slave.c +++ b/master/slave.c @@ -212,6 +212,7 @@ 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); @@ -220,6 +221,7 @@ void ec_slave_clear(ec_slave_t *slave /**< EtherCAT slave */) " slave about to be deleted.\n"); request->state = EC_INT_REQUEST_FAILURE; } +#endif wake_up_all(&slave->master->request_queue); From 3eda5173c6cdf0b8a851a0d1fb54c64507a739b1 Mon Sep 17 00:00:00 2001 From: Bjarne von Horn Date: Wed, 20 Sep 2023 12:45:17 +0200 Subject: [PATCH 12/13] Use fixed-size setip request --- master/fsm_eoe.c | 57 +++++++++++++++++++++--------------------------- 1 file changed, 25 insertions(+), 32 deletions(-) diff --git a/master/fsm_eoe.c b/master/fsm_eoe.c index 4788ab67..5c83f57e 100644 --- a/master/fsm_eoe.c +++ b/master/fsm_eoe.c @@ -159,31 +159,20 @@ int ec_fsm_eoe_prepare_set( 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; - } + // 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); @@ -191,9 +180,13 @@ int ec_fsm_eoe_prepare_set( 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, 0x01); // last fragment, no timestamps - EC_WRITE_U16(data + 2, 0x0000); // fragment no., offset, frame no. + 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) | @@ -208,37 +201,37 @@ int ec_fsm_eoe_prepare_set( if (req->mac_address_included) { memcpy(cur, req->mac_address, ETH_ALEN); - cur += ETH_ALEN; } + cur += ETH_ALEN; if (req->ip_address_included) { uint32_t swapped = htonl(req->ip_address); memcpy(cur, &swapped, 4); - cur += 4; } + cur += 4; if (req->subnet_mask_included) { uint32_t swapped = htonl(req->subnet_mask); memcpy(cur, &swapped, 4); - cur += 4; } + cur += 4; if (req->gateway_included) { uint32_t swapped = htonl(req->gateway); memcpy(cur, &swapped, 4); - cur += 4; } + cur += 4; if (req->dns_included) { uint32_t swapped = htonl(req->dns); memcpy(cur, &swapped, 4); - cur += 4; } + cur += 4; if (req->name_included) { memcpy(cur, req->name, EC_MAX_HOSTNAME_SIZE); - cur += EC_MAX_HOSTNAME_SIZE; } + cur += EC_MAX_HOSTNAME_SIZE; if (master->debug_level) { EC_SLAVE_DBG(slave, 0, "Set IP parameter request:\n"); From 038f73254316ab06ace0e521bb65271974a04c91 Mon Sep 17 00:00:00 2001 From: Florian Pose Date: Thu, 1 Feb 2024 13:05:55 +0100 Subject: [PATCH 13/13] Increase ioctl() version magic to 35. --- master/ioctl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/master/ioctl.h b/master/ioctl.h index d011ecae..ba959095 100644 --- a/master/ioctl.h +++ b/master/ioctl.h @@ -47,7 +47,7 @@ * * Increment this when changing the ioctl interface! */ -#define EC_IOCTL_VERSION_MAGIC 34 +#define EC_IOCTL_VERSION_MAGIC 35 // Command-line tool #define EC_IOCTL_MODULE EC_IOR(0x00, ec_ioctl_module_t)