Added feature flags to API.

This commit is contained in:
Florian Pose 2021-07-23 15:53:11 +02:00
parent f2e838a664
commit 2ee65b6387
12 changed files with 572 additions and 68 deletions

View File

@ -39,6 +39,11 @@
* request a master, to map process data, to communicate with slaves via CoE
* and to configure and activate the bus.
*
* Changes since version 1.5.2:
*
* - Added the ecrt_slave_config_flag() method and the EC_HAVE_FLAGS
* definition to check for its existence.
*
* Changes in version 1.5.2:
*
* - Added redundancy_active flag to ec_domain_state_t.
@ -191,6 +196,10 @@
*/
#define EC_HAVE_SYNC_TO
/** Defined if the method ecrt_slave_config_flag() is available.
*/
#define EC_HAVE_FLAGS
/*****************************************************************************/
/** End of list marker.
@ -1647,6 +1656,31 @@ int ecrt_slave_config_idn(
size_t size /**< Size of the \a data. */
);
/** Adds a feature flag to a slave configuration.
*
* Feature flags are a generic way to configure slave-specific behavior.
*
* Multiple calls with the same slave configuration and key will overwrite the
* configuration.
*
* The following flags may be available:
* - AssignToPdi: Zero (default) keeps the slave information interface (SII)
* assigned to EtherCAT (except during transition to PREOP). Non-zero
* assigns the SII to the slave controller side before going to PREOP and
* leaves it there until a write command happens.
*
* This method has to be called in non-realtime context before
* ecrt_master_activate().
*
* \retval 0 Success.
* \retval <0 Error code.
*/
int ecrt_slave_config_flag(
ec_slave_config_t *sc, /**< Slave configuration. */
const char *key, /**< Key as null-terminated ascii string. */
int32_t value /**< Value to store. */
);
/******************************************************************************
* Domain methods
*****************************************************************************/

View File

@ -797,3 +797,37 @@ int ecrt_slave_config_idn(ec_slave_config_t *sc, uint8_t drive_no,
}
/*****************************************************************************/
int ecrt_slave_config_flag(ec_slave_config_t *sc, const char *key,
int32_t value)
{
ec_ioctl_sc_flag_t io;
int ret;
io.config_index = sc->index;
io.key_size = strlen(key);
if (io.key_size <= 0) {
return -EINVAL;
}
io.key = malloc(io.key_size + 1);
if (!io.key) {
fprintf(stderr, "Failed to allocate %zu bytes of flag key memory.\n",
io.key_size);
return -ENOMEM;
}
strcpy(io.key, key);
io.value = value;
ret = ioctl(sc->master->fd, EC_IOCTL_SC_FLAG, &io);
if (EC_IOCTL_IS_ERROR(ret)) {
fprintf(stderr, "Failed to configure feature flag: %s\n",
strerror(EC_IOCTL_ERRNO(ret)));
return -EC_IOCTL_ERRNO(ret);
}
return 0;
}
/*****************************************************************************/

View File

@ -41,6 +41,7 @@ ec_master-objs := \
device.o \
domain.o \
eoe_request.o \
flag.o \
fmmu_config.o \
foe_request.o \
fsm_change.o \

69
master/flag.c Normal file
View File

@ -0,0 +1,69 @@
/*****************************************************************************
*
* Copyright (C) 2021 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
*
****************************************************************************/
/** \file
* Slave Configuration Feature Flag.
*/
/****************************************************************************/
#include <linux/slab.h>
#include "flag.h"
/*****************************************************************************/
/** SDO request constructor.
*/
int ec_flag_init(
ec_flag_t *flag, /**< Feature flag. */
const char *key, /**< Feature key. */
int32_t value /**< Feature value. */
)
{
if (!key || strlen(key) == 0) {
return -EINVAL;
}
if (!(flag->key = (uint8_t *) kmalloc(strlen(key) + 1, GFP_KERNEL))) {
return -ENOMEM;
}
strncpy(flag->key, key, strlen(key));
flag->value = value;
return 0;
}
/*****************************************************************************/
/** SDO request destructor.
*/
void ec_flag_clear(
ec_flag_t *flag /**< Feature flag. */
)
{
if (flag->key) {
kfree(flag->key);
flag->key = NULL;
}
}
/*****************************************************************************/

51
master/flag.h Normal file
View File

@ -0,0 +1,51 @@
/*****************************************************************************
*
* Copyright (C) 2021 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
*
****************************************************************************/
/**
\file
EtherCAT Slave Configuration Feature Flag.
*/
/****************************************************************************/
#ifndef __EC_FLAG_H__
#define __EC_FLAG_H__
#include <linux/list.h>
/****************************************************************************/
/** Slave configutation feature flag.
*/
typedef struct {
struct list_head list; /**< List item. */
char *key; /**< Flag key (null-terminated ASCII string. */
int32_t value; /**< Flag value (meaning depends on key). */
} ec_flag_t;
/****************************************************************************/
int ec_flag_init(ec_flag_t *, const char *, int32_t);
void ec_flag_clear(ec_flag_t *);
/****************************************************************************/
#endif

View File

@ -1232,6 +1232,7 @@ static ATTRIBUTES int ec_ioctl_config(
data.watchdog_intervals = sc->watchdog_intervals;
data.sdo_count = ec_slave_config_sdo_count(sc);
data.idn_count = ec_slave_config_idn_count(sc);
data.flag_count = ec_slave_config_flag_count(sc);
data.slave_position = sc->slave ? sc->slave->ring_position : -1;
data.dc_assign_activate = sc->dc_assign_activate;
for (i = 0; i < EC_SYNC_SIGNAL_COUNT; i++) {
@ -1497,6 +1498,69 @@ static ATTRIBUTES int ec_ioctl_config_idn(
/*****************************************************************************/
/** Get slave configuration feature flag information.
*
* \return Zero on success, otherwise a negative error code.
*/
static ATTRIBUTES int ec_ioctl_config_flag(
ec_master_t *master, /**< EtherCAT master. */
void *arg /**< ioctl() argument. */
)
{
ec_ioctl_config_flag_t *ioctl;
const ec_slave_config_t *sc;
const ec_flag_t *flag;
size_t size;
if (!(ioctl = kmalloc(sizeof(*ioctl), GFP_KERNEL))) {
return -ENOMEM;
}
if (copy_from_user(ioctl, (void __user *) arg, sizeof(*ioctl))) {
kfree(ioctl);
return -EFAULT;
}
if (down_interruptible(&master->master_sem)) {
kfree(ioctl);
return -EINTR;
}
if (!(sc = ec_master_get_config_const(
master, ioctl->config_index))) {
up(&master->master_sem);
EC_MASTER_ERR(master, "Slave config %u does not exist!\n",
ioctl->config_index);
kfree(ioctl);
return -EINVAL;
}
if (!(flag = ec_slave_config_get_flag_by_pos_const(
sc, ioctl->flag_pos))) {
up(&master->master_sem);
EC_MASTER_ERR(master, "Invalid flag position!\n");
kfree(ioctl);
return -EINVAL;
}
size = min((u32) strlen(flag->key), (u32) EC_MAX_FLAG_KEY_SIZE - 1);
memcpy(ioctl->key, flag->key, size);
ioctl->key[size] = 0x00;
ioctl->value = flag->value;
up(&master->master_sem);
if (copy_to_user((void __user *) arg, ioctl, sizeof(*ioctl))) {
kfree(ioctl);
return -EFAULT;
}
kfree(ioctl);
return 0;
}
/*****************************************************************************/
#ifdef EC_EOE
/** Get EoE handler information.
@ -3071,6 +3135,62 @@ static ATTRIBUTES int ec_ioctl_sc_idn(
/*****************************************************************************/
/** Configures a feature flag.
*
* \return Zero on success, otherwise a negative error code.
*/
static ATTRIBUTES int ec_ioctl_sc_flag(
ec_master_t *master, /**< EtherCAT master. */
void *arg, /**< ioctl() argument. */
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
)
{
ec_ioctl_sc_flag_t ioctl;
ec_slave_config_t *sc;
uint8_t *key;
int ret;
if (unlikely(!ctx->requested)) {
return -EPERM;
}
if (copy_from_user(&ioctl, (void __user *) arg, sizeof(ioctl))) {
return -EFAULT;
}
if (!ioctl.key_size) {
return -EINVAL;
}
if (!(key = kmalloc(ioctl.key_size + 1, GFP_KERNEL))) {
return -ENOMEM;
}
if (copy_from_user(key, (void __user *) ioctl.key, ioctl.key_size)) {
kfree(key);
return -EFAULT;
}
if (down_interruptible(&master->master_sem)) {
kfree(key);
return -EINTR;
}
if (!(sc = ec_master_get_config(master, ioctl.config_index))) {
up(&master->master_sem);
kfree(key);
return -ENOENT;
}
up(&master->master_sem); /** \todo sc could be invalidated */
ret = ecrt_slave_config_flag(sc, key, ioctl.value);
kfree(key);
return ret;
}
/*****************************************************************************/
/** Gets the domain's data size.
*
* \return Domain size, or a negative error code.
@ -4392,6 +4512,9 @@ long EC_IOCTL(
case EC_IOCTL_CONFIG_IDN:
ret = ec_ioctl_config_idn(master, arg);
break;
case EC_IOCTL_CONFIG_FLAG:
ret = ec_ioctl_config_flag(master, arg);
break;
#ifdef EC_EOE
case EC_IOCTL_EOE_HANDLER:
ret = ec_ioctl_eoe_handler(master, arg);
@ -4647,6 +4770,13 @@ long EC_IOCTL(
}
ret = ec_ioctl_sc_idn(master, arg, ctx);
break;
case EC_IOCTL_SC_FLAG:
if (!ctx->writable) {
ret = -EPERM;
break;
}
ret = ec_ioctl_sc_flag(master, arg, ctx);
break;
case EC_IOCTL_DOMAIN_SIZE:
ret = ec_ioctl_domain_size(master, arg, ctx);
break;

View File

@ -47,7 +47,7 @@
*
* Increment this when changing the ioctl interface!
*/
#define EC_IOCTL_VERSION_MAGIC 30
#define EC_IOCTL_VERSION_MAGIC 31
// Command-line tool
#define EC_IOCTL_MODULE EC_IOR(0x00, ec_ioctl_module_t)
@ -80,72 +80,74 @@
#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(0x1e, ec_ioctl_eoe_handler_t)
#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_DOMAIN_SIZE EC_IO(0x44)
#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x45)
#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x46)
#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x47)
#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x48, ec_ioctl_domain_state_t)
#define EC_IOCTL_SDO_REQUEST_INDEX EC_IOWR(0x49, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x4a, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x4b, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x4c, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x4d, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x4e, ec_ioctl_sdo_request_t)
#define EC_IOCTL_REG_REQUEST_DATA EC_IOWR(0x4f, ec_ioctl_reg_request_t)
#define EC_IOCTL_REG_REQUEST_STATE EC_IOWR(0x50, ec_ioctl_reg_request_t)
#define EC_IOCTL_REG_REQUEST_WRITE EC_IOWR(0x51, ec_ioctl_reg_request_t)
#define EC_IOCTL_REG_REQUEST_READ EC_IOWR(0x52, ec_ioctl_reg_request_t)
#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x53, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x54, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_READ EC_IOW(0x55, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x56, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_WRITE EC_IOWR(0x57, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_EXEC EC_IOWR(0x58, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_DATA EC_IOWR(0x59, ec_ioctl_voe_t)
#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x5a, size_t)
#define EC_IOCTL_SC_OVERLAPPING_IO EC_IOW(0x5b, ec_ioctl_config_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(0x40, ec_ioctl_sdo_request_t)
#define EC_IOCTL_REG_REQUEST_DATA EC_IOWR(0x41, 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)
#define EC_IOCTL_SC_OVERLAPPING_IO EC_IOW(0x5d, ec_ioctl_config_t)
/*****************************************************************************/
@ -486,6 +488,7 @@ typedef struct {
uint16_t watchdog_intervals;
uint32_t sdo_count;
uint32_t idn_count;
uint32_t flag_count;
int32_t slave_position;
uint16_t dc_assign_activate;
ec_sync_signal_t dc_sync[EC_SYNC_SIGNAL_COUNT];
@ -564,6 +567,22 @@ typedef struct {
/*****************************************************************************/
/** Maximum size for key.
*/
#define EC_MAX_FLAG_KEY_SIZE 128
typedef struct {
// inputs
uint32_t config_index;
uint32_t flag_pos;
// outputs
char key[EC_MAX_FLAG_KEY_SIZE];
int32_t value;
} ec_ioctl_config_flag_t;
/*****************************************************************************/
#ifdef EC_EOE
typedef struct {
@ -709,6 +728,16 @@ typedef struct {
/*****************************************************************************/
typedef struct {
// inputs
uint32_t config_index;
size_t key_size;
char *key;
int32_t value;
} ec_ioctl_sc_flag_t;
/*****************************************************************************/
typedef struct {
// inputs
uint32_t domain_index;

View File

@ -42,6 +42,7 @@
#include "globals.h"
#include "master.h"
#include "voe_handler.h"
#include "flag.h"
#include "slave_config.h"
@ -90,6 +91,7 @@ void ec_slave_config_init(
INIT_LIST_HEAD(&sc->reg_requests);
INIT_LIST_HEAD(&sc->voe_handlers);
INIT_LIST_HEAD(&sc->soe_configs);
INIT_LIST_HEAD(&sc->flags);
ec_coe_emerg_ring_init(&sc->emerg_ring, sc);
}
@ -109,6 +111,7 @@ void ec_slave_config_clear(
ec_voe_handler_t *voe, *next_voe;
ec_reg_request_t *reg, *next_reg;
ec_soe_request_t *soe, *next_soe;
ec_flag_t *flag, *next_flag;
ec_slave_config_detach(sc);
@ -151,6 +154,13 @@ void ec_slave_config_clear(
kfree(soe);
}
// free all flags
list_for_each_entry_safe(flag, next_flag, &sc->flags, list) {
list_del(&flag->list);
ec_flag_clear(flag);
kfree(flag);
}
ec_coe_emerg_ring_clear(&sc->emerg_ring);
}
@ -489,6 +499,50 @@ const ec_soe_request_t *ec_slave_config_get_idn_by_pos_const(
/*****************************************************************************/
/** Get the number of feature flags.
*
* \return Number of feature flags.
*/
unsigned int ec_slave_config_flag_count(
const ec_slave_config_t *sc /**< Slave configuration. */
)
{
const ec_flag_t *flag;
unsigned int count = 0;
list_for_each_entry(flag, &sc->flags, list) {
count++;
}
return count;
}
/*****************************************************************************/
/** Finds a flag via its position in the list.
*
* Const version.
*
* \return Search result, or NULL.
*/
const ec_flag_t *ec_slave_config_get_flag_by_pos_const(
const ec_slave_config_t *sc, /**< Slave configuration. */
unsigned int pos /**< Position in the list. */
)
{
const ec_flag_t *flag;
list_for_each_entry(flag, &sc->flags, list) {
if (pos--)
continue;
return flag;
}
return NULL;
}
/*****************************************************************************/
/** Finds a CoE handler via its position in the list.
*
* \return Search result, or NULL.
@ -564,25 +618,51 @@ void ec_slave_config_expire_disconnected_requests(
ec_sdo_request_t *sdo_req;
ec_reg_request_t *reg_req;
if (sc->slave) { return; }
if (sc->slave) {
return;
}
list_for_each_entry(sdo_req, &sc->sdo_requests, list) {
if (sdo_req->state == EC_INT_REQUEST_QUEUED ||
sdo_req->state == EC_INT_REQUEST_BUSY) {
EC_CONFIG_DBG(sc, 1, "Aborting SDO request; no slave attached.\n");
EC_CONFIG_DBG(sc, 1,
"Aborting SDO request; no slave attached.\n");
sdo_req->state = EC_INT_REQUEST_FAILURE;
}
}
list_for_each_entry(reg_req, &sc->reg_requests, list) {
if (reg_req->state == EC_INT_REQUEST_QUEUED ||
reg_req->state == EC_INT_REQUEST_BUSY) {
EC_CONFIG_DBG(sc, 1, "Aborting register request; no slave attached.\n");
EC_CONFIG_DBG(sc, 1,
"Aborting register request; no slave attached.\n");
reg_req->state = EC_INT_REQUEST_FAILURE;
}
}
}
/*****************************************************************************/
/** Finds a flag.
*
* \return Search result, or NULL.
*/
ec_flag_t *ec_slave_config_find_flag(
ec_slave_config_t *sc, /**< Slave configuration. */
const uint8_t *key /**< Flag key. */
)
{
ec_flag_t *flag;
list_for_each_entry(flag, &sc->flags, list) {
if (!strcmp(flag->key, key)) {
return flag;
}
}
return NULL;
}
/******************************************************************************
* Application interface
*****************************************************************************/
@ -1315,6 +1395,42 @@ int ecrt_slave_config_idn(ec_slave_config_t *sc, uint8_t drive_no,
/*****************************************************************************/
int ecrt_slave_config_flag(ec_slave_config_t *sc, const char *key,
int32_t value)
{
ec_flag_t *flag;
EC_CONFIG_DBG(sc, 1, "%s(sc = 0x%p, key = %s, value = %i)\n",
__func__, sc, key, value);
flag = ec_slave_config_find_flag(sc, key);
if (flag) {
flag->value = value; // overwrite value
}
else { // new flag
int ret;
if (!(flag = (ec_flag_t *) kmalloc(sizeof(ec_flag_t), GFP_KERNEL))) {
EC_CONFIG_ERR(sc, "Failed to allocate memory for flag!\n");
return -ENOMEM;
}
ret = ec_flag_init(flag, key, value);
if (ret) {
kfree(flag);
return ret;
}
down(&sc->master->master_sem);
list_add_tail(&flag->list, &sc->flags);
up(&sc->master->master_sem);
}
return 0;
}
/*****************************************************************************/
/** \cond */
EXPORT_SYMBOL(ecrt_slave_config_sync_manager);
@ -1341,6 +1457,7 @@ EXPORT_SYMBOL(ecrt_slave_config_create_voe_handler);
EXPORT_SYMBOL(ecrt_slave_config_create_reg_request);
EXPORT_SYMBOL(ecrt_slave_config_state);
EXPORT_SYMBOL(ecrt_slave_config_idn);
EXPORT_SYMBOL(ecrt_slave_config_flag);
/** \endcond */

View File

@ -44,6 +44,7 @@
#include "sync_config.h"
#include "fmmu_config.h"
#include "coe_emerg_ring.h"
#include "flag.h"
/*****************************************************************************/
@ -147,6 +148,7 @@ struct ec_slave_config {
struct list_head voe_handlers; /**< List of VoE handlers. */
struct list_head reg_requests; /**< List of register requests. */
struct list_head soe_configs; /**< List of SoE configurations. */
struct list_head flags; /**< List of feature flags. */
ec_coe_emerg_ring_t emerg_ring; /**< CoE emergency ring buffer. */
};
@ -168,6 +170,9 @@ const ec_sdo_request_t *ec_slave_config_get_sdo_by_pos_const(
unsigned int ec_slave_config_idn_count(const ec_slave_config_t *);
const ec_soe_request_t *ec_slave_config_get_idn_by_pos_const(
const ec_slave_config_t *, unsigned int);
unsigned int ec_slave_config_flag_count(const ec_slave_config_t *);
const ec_flag_t *ec_slave_config_get_flag_by_pos_const(
const ec_slave_config_t *, unsigned int);
ec_sdo_request_t *ec_slave_config_find_sdo_request(ec_slave_config_t *,
unsigned int);
ec_reg_request_t *ec_slave_config_find_reg_request(ec_slave_config_t *,

View File

@ -154,6 +154,7 @@ void CommandConfig::showDetailedConfigs(
ec_ioctl_config_pdo_entry_t entry;
ec_ioctl_config_sdo_t sdo;
ec_ioctl_config_idn_t idn;
ec_ioctl_config_flag_t flag;
string indent(doIndent ? " " : "");
for (configIter = configList.begin();
@ -293,6 +294,19 @@ void CommandConfig::showDetailedConfigs(
} else {
cout << indent << " None." << endl;
}
cout << indent << "Feature flags:" << endl;
if (configIter->flag_count) {
for (j = 0; j < configIter->flag_count; j++) {
m.getConfigFlag(&flag, configIter->config_index, j);
cout << indent << " " << flag.key
<< ": " << flag.value << endl;
}
} else {
cout << indent << " None." << endl;
}
if (configIter->dc_assign_activate) {
int i;

View File

@ -218,6 +218,24 @@ void MasterDevice::getConfigIdn(
/****************************************************************************/
void MasterDevice::getConfigFlag(
ec_ioctl_config_flag_t *data,
unsigned int index,
unsigned int pos
)
{
data->config_index = index;
data->flag_pos = pos;
if (ioctl(fd, EC_IOCTL_CONFIG_FLAG, data) < 0) {
stringstream err;
err << "Failed to get slave config flag: " << strerror(errno);
throw MasterDeviceException(err);
}
}
/****************************************************************************/
void MasterDevice::getDomain(ec_ioctl_domain_t *data, unsigned int index)
{
data->index = index;

View File

@ -134,6 +134,8 @@ class MasterDevice
uint8_t, uint16_t, uint8_t);
void getConfigSdo(ec_ioctl_config_sdo_t *, unsigned int, unsigned int);
void getConfigIdn(ec_ioctl_config_idn_t *, unsigned int, unsigned int);
void getConfigFlag(ec_ioctl_config_flag_t *, unsigned int,
unsigned int);
void getDomain(ec_ioctl_domain_t *, unsigned int);
void getFmmu(ec_ioctl_domain_fmmu_t *, unsigned int, unsigned int);
void getData(ec_ioctl_domain_data_t *, unsigned int, unsigned int,