From a178c9e452a63030b56da4a0dc5e280a289d3163 Mon Sep 17 00:00:00 2001 From: Florian Pose Date: Fri, 23 Jul 2021 15:53:11 +0200 Subject: [PATCH] Added feature flags to API. --- include/ecrt.h | 34 +++++++++ lib/slave_config.c | 34 +++++++++ master/Kbuild.in | 1 + master/flag.c | 69 +++++++++++++++++++ master/flag.h | 51 ++++++++++++++ master/ioctl.c | 130 ++++++++++++++++++++++++++++++++++ master/ioctl.h | 153 ++++++++++++++++++++++++----------------- master/slave_config.c | 113 ++++++++++++++++++++++++++++++ master/slave_config.h | 5 ++ tool/CommandConfig.cpp | 14 ++++ tool/MasterDevice.cpp | 18 +++++ tool/MasterDevice.h | 2 + 12 files changed, 562 insertions(+), 62 deletions(-) create mode 100644 master/flag.c create mode 100644 master/flag.h diff --git a/include/ecrt.h b/include/ecrt.h index 9d673ecb..5292e240 100644 --- a/include/ecrt.h +++ b/include/ecrt.h @@ -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. @@ -1634,6 +1643,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 *****************************************************************************/ diff --git a/lib/slave_config.c b/lib/slave_config.c index d045e090..ea28f75a 100644 --- a/lib/slave_config.c +++ b/lib/slave_config.c @@ -780,3 +780,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; +} + +/*****************************************************************************/ diff --git a/master/Kbuild.in b/master/Kbuild.in index 47279777..98b9e6cd 100644 --- a/master/Kbuild.in +++ b/master/Kbuild.in @@ -40,6 +40,7 @@ ec_master-objs := \ datagram_pair.o \ device.o \ domain.o \ + flag.o \ fmmu_config.o \ foe_request.o \ fsm_change.o \ diff --git a/master/flag.c b/master/flag.c new file mode 100644 index 00000000..c0e23c31 --- /dev/null +++ b/master/flag.c @@ -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 + +#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; + } +} + +/*****************************************************************************/ diff --git a/master/flag.h b/master/flag.h new file mode 100644 index 00000000..e7679c2f --- /dev/null +++ b/master/flag.h @@ -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 + +/****************************************************************************/ + +/** 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 diff --git a/master/ioctl.c b/master/ioctl.c index 69fb3552..100db4bb 100644 --- a/master/ioctl.c +++ b/master/ioctl.c @@ -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. @@ -2939,6 +3003,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. @@ -4253,6 +4373,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); @@ -4501,6 +4624,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; diff --git a/master/ioctl.h b/master/ioctl.h index 10f010ec..3991e406 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 30 +#define EC_IOCTL_VERSION_MAGIC 31 // Command-line tool #define EC_IOCTL_MODULE EC_IOR(0x00, ec_ioctl_module_t) @@ -79,71 +79,73 @@ #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(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, uint64_t) -#define EC_IOCTL_SYNC_REF EC_IO(0x29) -#define EC_IOCTL_SYNC_REF_TO EC_IOW(0x2a, uint64_t) -#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) +#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) /*****************************************************************************/ @@ -484,6 +486,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]; @@ -561,6 +564,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 { @@ -675,6 +694,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; diff --git a/master/slave_config.c b/master/slave_config.c index cf5d501f..50921caf 100644 --- a/master/slave_config.c +++ b/master/slave_config.c @@ -42,6 +42,7 @@ #include "globals.h" #include "master.h" #include "voe_handler.h" +#include "flag.h" #include "slave_config.h" @@ -89,6 +90,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); } @@ -108,6 +110,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); @@ -150,6 +153,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); } @@ -453,6 +463,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. @@ -517,6 +571,28 @@ ec_voe_handler_t *ec_slave_config_find_voe_handler( return NULL; } +/*****************************************************************************/ + +/** 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 *****************************************************************************/ @@ -1238,6 +1314,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); @@ -1263,6 +1375,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 */ diff --git a/master/slave_config.h b/master/slave_config.h index 9fd633dc..12a90ebb 100644 --- a/master/slave_config.h +++ b/master/slave_config.h @@ -44,6 +44,7 @@ #include "sync_config.h" #include "fmmu_config.h" #include "coe_emerg_ring.h" +#include "flag.h" /*****************************************************************************/ @@ -145,6 +146,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. */ }; @@ -166,6 +168,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 *, diff --git a/tool/CommandConfig.cpp b/tool/CommandConfig.cpp index b9fa1b64..01cd1f3a 100644 --- a/tool/CommandConfig.cpp +++ b/tool/CommandConfig.cpp @@ -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; diff --git a/tool/MasterDevice.cpp b/tool/MasterDevice.cpp index ca023246..32c31478 100644 --- a/tool/MasterDevice.cpp +++ b/tool/MasterDevice.cpp @@ -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; diff --git a/tool/MasterDevice.h b/tool/MasterDevice.h index 7398f978..16db6ac7 100644 --- a/tool/MasterDevice.h +++ b/tool/MasterDevice.h @@ -117,6 +117,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,