Implemented EoE Set IP parameter request via command-line tool.

This commit is contained in:
Florian Pose 2014-11-12 14:42:17 +01:00
parent 36beb63ca1
commit a03d091ac0
19 changed files with 1374 additions and 73 deletions

View File

@ -40,10 +40,12 @@ ec_master-objs := \
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 \

View File

@ -37,12 +37,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 \

71
master/eoe_request.c Normal file
View File

@ -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;
}
/*****************************************************************************/

77
master/eoe_request.h Normal file
View File

@ -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

485
master/fsm_eoe.c Normal file
View File

@ -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. */
)
{
}
/*****************************************************************************/

74
master/fsm_eoe.h Normal file
View File

@ -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

View File

@ -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;
}
/*****************************************************************************/

View File

@ -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. */
};
/*****************************************************************************/

View File

@ -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

View File

@ -1550,6 +1550,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.
@ -4205,6 +4288,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;

View File

@ -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 @@ 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;

View File

@ -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) {

View File

@ -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. */
};

258
tool/CommandIp.cpp Normal file
View File

@ -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);
}
/****************************************************************************/

55
tool/CommandIp.h Normal file
View File

@ -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

View File

@ -48,6 +48,7 @@ ethercat_SOURCES = \
CommandFoeRead.cpp \
CommandFoeWrite.cpp \
CommandGraph.cpp \
CommandIp.cpp \
CommandMaster.cpp \
CommandPdos.cpp \
CommandRegRead.cpp \
@ -90,6 +91,7 @@ noinst_HEADERS = \
CommandFoeRead.h \
CommandFoeWrite.h \
CommandGraph.h \
CommandIp.h \
CommandMaster.h \
CommandPdos.h \
CommandRegRead.h \

View File

@ -585,4 +585,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);
}
}
}
/*****************************************************************************/

View File

@ -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:
@ -144,6 +161,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;}

View File

@ -48,6 +48,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"
@ -288,6 +289,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());