Added ecrt_master_link_state() to retrieve information about a redundant link.
--- 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
--- 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;
--- 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;
--- 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;
--- 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);