# HG changeset patch # User Florian Pose # Date 1338455038 -7200 # Node ID cf9db49bcce8048ac874801d35d5ca9bd48ba81f # Parent 6f100ee02e652259e39817e6712a5cd8e40c40af Added ecrt_master_link_state() to retrieve information about a redundant link. diff -r 6f100ee02e65 -r cf9db49bcce8 include/ecrt.h --- a/include/ecrt.h Thu May 31 09:50:29 2012 +0200 +++ b/include/ecrt.h Thu May 31 11:03:58 2012 +0200 @@ -42,6 +42,8 @@ * Changed since 1.5: * * - Added redundancy_active flag to ec_domain_state_t. + * - Added ecrt_master_link_state() method and ec_master_link_state_t to query + * the state of a redundant link. * * Changes in version 1.5: * @@ -200,6 +202,30 @@ /*****************************************************************************/ +/** Redundant link state. + * + * This is used for the output parameter of ecrt_master_link_state(). + * + * \see ecrt_master_link_state(). + */ +typedef struct { + unsigned int slaves_responding; /**< Sum of responding slaves on the given + link. */ + unsigned int al_states : 4; /**< Application-layer states of the slaves on + the given link. The states are coded in the + lower 4 bits. If a bit is set, it means + that at least one slave in the bus is in the + corresponding state: + - Bit 0: \a INIT + - Bit 1: \a PREOP + - Bit 2: \a SAFEOP + - Bit 3: \a OP */ + unsigned int link_up : 1; /**< \a true, if the given Ethernet link is up. + */ +} ec_master_link_state_t; + +/*****************************************************************************/ + /** Slave configuration state. * * This is used as an output parameter of ecrt_slave_config_state(). @@ -855,12 +881,29 @@ /** Reads the current master state. * * Stores the master state information in the given \a state structure. + * + * This method returns a global state. For the link-specific states in a + * redundant bus topology, use the ecrt_master_link_state() method. */ void ecrt_master_state( const ec_master_t *master, /**< EtherCAT master. */ ec_master_state_t *state /**< Structure to store the information. */ ); +/** Reads the current state of a redundant link. + * + * Stores the link state information in the given \a state structure. + * + * \return Zero on success, otherwise negative error code. + */ +int ecrt_master_link_state( + const ec_master_t *master, /**< EtherCAT master. */ + unsigned int dev_idx, /**< Index of the device (0 = main device, 1 = + first backup device, ...). */ + ec_master_link_state_t *state /**< Structure to store the information. + */ + ); + /** Sets the application time. * * The master has to know the application's time when operating slaves with diff -r 6f100ee02e65 -r cf9db49bcce8 lib/master.c --- a/lib/master.c Thu May 31 09:50:29 2012 +0200 +++ b/lib/master.c Thu May 31 11:03:58 2012 +0200 @@ -235,11 +235,14 @@ for ( i = 0; i < EC_MAX_PORTS; i++ ) { slave_info->ports[i].desc = data.ports[i].desc; slave_info->ports[i].link.link_up = data.ports[i].link.link_up; - slave_info->ports[i].link.loop_closed = data.ports[i].link.loop_closed; - slave_info->ports[i].link.signal_detected = data.ports[i].link.signal_detected; + slave_info->ports[i].link.loop_closed = + data.ports[i].link.loop_closed; + slave_info->ports[i].link.signal_detected = + data.ports[i].link.signal_detected; slave_info->ports[i].receive_time = data.ports[i].receive_time; slave_info->ports[i].next_slave = data.ports[i].next_slave; - slave_info->ports[i].delay_to_next_dc = data.ports[i].delay_to_next_dc; + slave_info->ports[i].delay_to_next_dc = + data.ports[i].delay_to_next_dc; } slave_info->al_state = data.al_state; slave_info->error_flag = data.error_flag; @@ -256,8 +259,9 @@ { ec_ioctl_slave_sync_t data; - if (sync_index >= EC_MAX_SYNC_MANAGERS) + if (sync_index >= EC_MAX_SYNC_MANAGERS) { return -ENOENT; + } memset(&data, 0x00, sizeof(ec_ioctl_slave_sync_t)); data.slave_position = slave_position; @@ -552,6 +556,21 @@ /*****************************************************************************/ +int ecrt_master_link_state(const ec_master_t *master, unsigned int dev_idx, + ec_master_link_state_t *state) +{ + ec_ioctl_link_state_t io; + + io.dev_idx = dev_idx; + io.state = state; + if (ioctl(master->fd, EC_IOCTL_MASTER_LINK_STATE, &io) == -1) { + fprintf(stderr, "Failed to get link state: %s\n", strerror(errno)); + return -errno; + } +} + +/*****************************************************************************/ + void ecrt_master_application_time(ec_master_t *master, uint64_t app_time) { ec_ioctl_app_time_t data; diff -r 6f100ee02e65 -r cf9db49bcce8 master/cdev.c --- a/master/cdev.c Thu May 31 09:50:29 2012 +0200 +++ b/master/cdev.c Thu May 31 11:03:58 2012 +0200 @@ -1829,6 +1829,40 @@ /** Get the master state. */ +int ec_cdev_ioctl_master_link_state( + ec_master_t *master, /**< EtherCAT master. */ + unsigned long arg, /**< ioctl() argument. */ + ec_cdev_priv_t *priv /**< Private data structure of file handle. */ + ) +{ + ec_ioctl_link_state_t ioctl; + ec_master_link_state_t state; + int ret; + + if (unlikely(!priv->requested)) { + return -EPERM; + } + + if (copy_from_user(&ioctl, (void __user *) arg, sizeof(ioctl))) { + return -EFAULT; + } + + ret = ecrt_master_link_state(master, ioctl.dev_idx, &state); + if (ret < 0) { + return ret; + } + + if (copy_to_user((void __user *) ioctl.state, &state, sizeof(state))) { + return -EFAULT; + } + + return 0; +} + +/*****************************************************************************/ + +/** Get the master state. + */ int ec_cdev_ioctl_app_time( ec_master_t *master, /**< EtherCAT master. */ unsigned long arg, /**< ioctl() argument. */ @@ -3629,6 +3663,9 @@ case EC_IOCTL_MASTER_STATE: ret = ec_cdev_ioctl_master_state(master, arg, priv); break; + case EC_IOCTL_MASTER_LINK_STATE: + ret = ec_cdev_ioctl_master_link_state(master, arg, priv); + break; case EC_IOCTL_APP_TIME: if (!(filp->f_mode & FMODE_WRITE)) { ret = -EPERM; diff -r 6f100ee02e65 -r cf9db49bcce8 master/ioctl.h --- a/master/ioctl.h Thu May 31 09:50:29 2012 +0200 +++ b/master/ioctl.h Thu May 31 11:03:58 2012 +0200 @@ -56,7 +56,7 @@ * * Increment this when changing the ioctl interface! */ -#define EC_IOCTL_VERSION_MAGIC 17 +#define EC_IOCTL_VERSION_MAGIC 18 // Command-line tool #define EC_IOCTL_MODULE EC_IOR(0x00, ec_ioctl_module_t) @@ -101,42 +101,43 @@ #define EC_IOCTL_SEND EC_IO(0x23) #define EC_IOCTL_RECEIVE EC_IO(0x24) #define EC_IOCTL_MASTER_STATE EC_IOR(0x25, ec_master_state_t) -#define EC_IOCTL_APP_TIME EC_IOW(0x26, ec_ioctl_app_time_t) -#define EC_IOCTL_SYNC_REF EC_IO(0x27) -#define EC_IOCTL_SYNC_SLAVES EC_IO(0x28) -#define EC_IOCTL_SYNC_MON_QUEUE EC_IO(0x29) -#define EC_IOCTL_SYNC_MON_PROCESS EC_IOR(0x2a, uint32_t) -#define EC_IOCTL_RESET EC_IO(0x2b) -#define EC_IOCTL_SC_SYNC EC_IOW(0x2c, ec_ioctl_config_t) -#define EC_IOCTL_SC_WATCHDOG EC_IOW(0x2d, ec_ioctl_config_t) -#define EC_IOCTL_SC_ADD_PDO EC_IOW(0x2e, ec_ioctl_config_pdo_t) -#define EC_IOCTL_SC_CLEAR_PDOS EC_IOW(0x2f, ec_ioctl_config_pdo_t) -#define EC_IOCTL_SC_ADD_ENTRY EC_IOW(0x30, ec_ioctl_add_pdo_entry_t) -#define EC_IOCTL_SC_CLEAR_ENTRIES EC_IOW(0x31, ec_ioctl_config_pdo_t) -#define EC_IOCTL_SC_REG_PDO_ENTRY EC_IOWR(0x32, ec_ioctl_reg_pdo_entry_t) -#define EC_IOCTL_SC_DC EC_IOW(0x33, ec_ioctl_config_t) -#define EC_IOCTL_SC_SDO EC_IOW(0x34, ec_ioctl_sc_sdo_t) -#define EC_IOCTL_SC_SDO_REQUEST EC_IOWR(0x35, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SC_VOE EC_IOWR(0x36, ec_ioctl_voe_t) -#define EC_IOCTL_SC_STATE EC_IOWR(0x37, ec_ioctl_sc_state_t) -#define EC_IOCTL_SC_IDN EC_IOW(0x38, ec_ioctl_sc_idn_t) -#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x39) -#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x3a) -#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x3b) -#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x3c, ec_ioctl_domain_state_t) -#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x3d, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x3e, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x3f, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x40, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x41, ec_ioctl_sdo_request_t) -#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x42, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x43, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_READ EC_IOW(0x44, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x45, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_WRITE EC_IOWR(0x46, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_EXEC EC_IOWR(0x47, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_DATA EC_IOWR(0x48, ec_ioctl_voe_t) -#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x49, size_t) +#define EC_IOCTL_MASTER_LINK_STATE EC_IOWR(0x26, ec_ioctl_link_state_t) +#define EC_IOCTL_APP_TIME EC_IOW(0x27, ec_ioctl_app_time_t) +#define EC_IOCTL_SYNC_REF EC_IO(0x28) +#define EC_IOCTL_SYNC_SLAVES EC_IO(0x29) +#define EC_IOCTL_SYNC_MON_QUEUE EC_IO(0x2a) +#define EC_IOCTL_SYNC_MON_PROCESS EC_IOR(0x2b, uint32_t) +#define EC_IOCTL_RESET EC_IO(0x2c) +#define EC_IOCTL_SC_SYNC EC_IOW(0x2d, ec_ioctl_config_t) +#define EC_IOCTL_SC_WATCHDOG EC_IOW(0x2e, ec_ioctl_config_t) +#define EC_IOCTL_SC_ADD_PDO EC_IOW(0x2f, ec_ioctl_config_pdo_t) +#define EC_IOCTL_SC_CLEAR_PDOS EC_IOW(0x20, ec_ioctl_config_pdo_t) +#define EC_IOCTL_SC_ADD_ENTRY EC_IOW(0x31, ec_ioctl_add_pdo_entry_t) +#define EC_IOCTL_SC_CLEAR_ENTRIES EC_IOW(0x32, ec_ioctl_config_pdo_t) +#define EC_IOCTL_SC_REG_PDO_ENTRY EC_IOWR(0x33, ec_ioctl_reg_pdo_entry_t) +#define EC_IOCTL_SC_DC EC_IOW(0x34, ec_ioctl_config_t) +#define EC_IOCTL_SC_SDO EC_IOW(0x35, ec_ioctl_sc_sdo_t) +#define EC_IOCTL_SC_SDO_REQUEST EC_IOWR(0x36, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SC_VOE EC_IOWR(0x37, ec_ioctl_voe_t) +#define EC_IOCTL_SC_STATE EC_IOWR(0x38, ec_ioctl_sc_state_t) +#define EC_IOCTL_SC_IDN EC_IOW(0x39, ec_ioctl_sc_idn_t) +#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x3a) +#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x3b) +#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x3c) +#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x3d, ec_ioctl_domain_state_t) +#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x3e, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x3f, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x30, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x41, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x42, ec_ioctl_sdo_request_t) +#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x43, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x44, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_READ EC_IOW(0x45, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x46, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_WRITE EC_IOWR(0x47, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_EXEC EC_IOWR(0x48, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_DATA EC_IOWR(0x49, ec_ioctl_voe_t) +#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x4a, size_t) /*****************************************************************************/ @@ -673,6 +674,16 @@ typedef struct { // inputs + uint32_t dev_idx; + + // outputs + ec_master_link_state_t *state; +} ec_ioctl_link_state_t; + +/*****************************************************************************/ + +typedef struct { + // inputs uint64_t app_time; } ec_ioctl_app_time_t; diff -r 6f100ee02e65 -r cf9db49bcce8 master/master.c --- a/master/master.c Thu May 31 09:50:29 2012 +0200 +++ b/master/master.c Thu May 31 11:03:58 2012 +0200 @@ -2507,6 +2507,22 @@ /*****************************************************************************/ +int ecrt_master_link_state(const ec_master_t *master, unsigned int dev_idx, + ec_master_link_state_t *state) +{ + if (dev_idx >= EC_NUM_DEVICES) { + return -EINVAL; + } + + state->slaves_responding = master->fsm.slaves_responding[dev_idx]; + state->al_states = master->fsm.slave_states[dev_idx]; + state->link_up = master->devices[dev_idx].link_state; + + return 0; +} + +/*****************************************************************************/ + void ecrt_master_application_time(ec_master_t *master, uint64_t app_time) { master->app_time = app_time; @@ -2980,6 +2996,7 @@ EXPORT_SYMBOL(ecrt_master_get_slave); EXPORT_SYMBOL(ecrt_master_slave_config); EXPORT_SYMBOL(ecrt_master_state); +EXPORT_SYMBOL(ecrt_master_link_state); EXPORT_SYMBOL(ecrt_master_application_time); EXPORT_SYMBOL(ecrt_master_sync_reference_clock); EXPORT_SYMBOL(ecrt_master_sync_slave_clocks);