# HG changeset patch # User Florian Pose # Date 1250849716 -7200 # Node ID 0c484ee12d89fe61a3d6902c64ce3f30d79f0a57 # Parent 4844a843391551c0da3c045d2ae6417e31af2545 DC synchrony monitoring methods. diff -r 4844a8433915 -r 0c484ee12d89 TODO --- a/TODO Fri Aug 21 09:46:29 2009 +0200 +++ b/TODO Fri Aug 21 12:15:16 2009 +0200 @@ -20,7 +20,6 @@ "System Time" register instead of using the application time. - Check if register 0x0980 is working, to avoid clearing it when configuring. - - Create an interface to query the System Time Difference registers. * Remove byte-swapping functions from user space. * EoE: - Only execute one EoE handler per cycle. diff -r 4844a8433915 -r 0c484ee12d89 include/ecrt.h --- a/include/ecrt.h Fri Aug 21 09:46:29 2009 +0200 +++ b/include/ecrt.h Fri Aug 21 12:15:16 2009 +0200 @@ -45,7 +45,9 @@ * ecrt_slave_config_dc() to configure a slave for cyclic operation, and * ecrt_master_application_time(), ecrt_master_sync_reference_clock() and * ecrt_master_sync_slave_clocks() for offset and drift compensation. The - * EC_TIMEVAL2NANO() macro can be used for epoch time conversion. + * EC_TIMEVAL2NANO() macro can be used for epoch time conversion, while the + * ecrt_master_sync_monitor_queue() and ecrt_master_sync_monitor_process() + * methods can be used to monitor the synchrony. * - Improved the callback mechanism. ecrt_master_callbacks() now takes two * callback functions for sending and receiving datagrams. * ecrt_master_send_ext() is used to execute the sending of non-application @@ -775,6 +777,28 @@ ec_master_t *master /**< EtherCAT master. */ ); +/** Queues the DC synchonity monitoring datagram for sending. + * + * The datagram broadcast-reads all "System time difference" registers (\a + * 0x092c) to get an upper estiomation of the DC synchony. The result can be + * checked with the ecrt_master_sync_monitor_process() method. + */ +void ecrt_master_sync_monitor_queue( + ec_master_t *master /**< EtherCAT master. */ + ); + +/** Processes the DC synchonity monitoring datagram. + * + * If the sync monitoring datagram was sent before with + * ecrt_master_sync_monitor_queue(), the result can be queried with this + * method. + * + * \return Upper estination of the maximum time difference in ns. + */ +uint32_t ecrt_master_sync_monitor_process( + ec_master_t *master /**< EtherCAT master. */ + ); + /****************************************************************************** * Slave configuration methods *****************************************************************************/ diff -r 4844a8433915 -r 0c484ee12d89 lib/master.c --- a/lib/master.c Fri Aug 21 09:46:29 2009 +0200 +++ b/lib/master.c Fri Aug 21 12:15:16 2009 +0200 @@ -404,3 +404,28 @@ } /*****************************************************************************/ + +void ecrt_master_sync_monitor_queue(ec_master_t *master) +{ + if (ioctl(master->fd, EC_IOCTL_SYNC_MON_QUEUE, NULL) == -1) { + fprintf(stderr, "Failed to queue sync monitor datagram: %s\n", + strerror(errno)); + } +} + +/*****************************************************************************/ + +uint32_t ecrt_master_sync_monitor_process(ec_master_t *master) +{ + uint32_t time_diff; + + if (ioctl(master->fd, EC_IOCTL_SYNC_MON_PROCESS, &time_diff) == -1) { + time_diff = 0xffffffff; + fprintf(stderr, "Failed to process sync monitor datagram: %s\n", + strerror(errno)); + } + + return time_diff; +} + +/*****************************************************************************/ diff -r 4844a8433915 -r 0c484ee12d89 master/cdev.c --- a/master/cdev.c Fri Aug 21 09:46:29 2009 +0200 +++ b/master/cdev.c Fri Aug 21 12:15:16 2009 +0200 @@ -1787,6 +1787,50 @@ /*****************************************************************************/ +/** Queue the sync monitoring datagram. + */ +int ec_cdev_ioctl_sync_mon_queue( + ec_master_t *master, /**< EtherCAT master. */ + unsigned long arg, /**< ioctl() argument. */ + ec_cdev_priv_t *priv /**< Private data structure of file handle. */ + ) +{ + if (unlikely(!priv->requested)) + return -EPERM; + + down(&master->io_sem); + ecrt_master_sync_monitor_queue(master); + up(&master->io_sem); + return 0; +} + +/*****************************************************************************/ + +/** Processes the sync monitoring datagram. + */ +int ec_cdev_ioctl_sync_mon_process( + ec_master_t *master, /**< EtherCAT master. */ + unsigned long arg, /**< ioctl() argument. */ + ec_cdev_priv_t *priv /**< Private data structure of file handle. */ + ) +{ + uint32_t time_diff; + + if (unlikely(!priv->requested)) + return -EPERM; + + down(&master->io_sem); + time_diff = ecrt_master_sync_monitor_process(master); + up(&master->io_sem); + + if (copy_to_user((void __user *) arg, &time_diff, sizeof(time_diff))) + return -EFAULT; + + return 0; +} + +/*****************************************************************************/ + /** Configure a sync manager. */ int ec_cdev_ioctl_sc_sync( @@ -3306,6 +3350,14 @@ if (!(filp->f_mode & FMODE_WRITE)) return -EPERM; return ec_cdev_ioctl_sync_slaves(master, arg, priv); + case EC_IOCTL_SYNC_MON_QUEUE: + if (!(filp->f_mode & FMODE_WRITE)) + return -EPERM; + return ec_cdev_ioctl_sync_mon_queue(master, arg, priv); + case EC_IOCTL_SYNC_MON_PROCESS: + if (!(filp->f_mode & FMODE_WRITE)) + return -EPERM; + return ec_cdev_ioctl_sync_mon_process(master, arg, priv); case EC_IOCTL_SC_SYNC: if (!(filp->f_mode & FMODE_WRITE)) return -EPERM; diff -r 4844a8433915 -r 0c484ee12d89 master/ioctl.h --- a/master/ioctl.h Fri Aug 21 09:46:29 2009 +0200 +++ b/master/ioctl.h Fri Aug 21 12:15:16 2009 +0200 @@ -93,34 +93,36 @@ #define EC_IOCTL_APP_TIME EC_IOW(0x21, ec_ioctl_app_time_t) #define EC_IOCTL_SYNC_REF EC_IO(0x22) #define EC_IOCTL_SYNC_SLAVES EC_IO(0x23) -#define EC_IOCTL_SC_SYNC EC_IOW(0x24, ec_ioctl_config_t) -#define EC_IOCTL_SC_WATCHDOG EC_IOW(0x25, ec_ioctl_config_t) -#define EC_IOCTL_SC_ADD_PDO EC_IOW(0x26, ec_ioctl_config_pdo_t) -#define EC_IOCTL_SC_CLEAR_PDOS EC_IOW(0x27, ec_ioctl_config_pdo_t) -#define EC_IOCTL_SC_ADD_ENTRY EC_IOW(0x28, ec_ioctl_add_pdo_entry_t) -#define EC_IOCTL_SC_CLEAR_ENTRIES EC_IOW(0x29, ec_ioctl_config_pdo_t) -#define EC_IOCTL_SC_REG_PDO_ENTRY EC_IOWR(0x2a, ec_ioctl_reg_pdo_entry_t) -#define EC_IOCTL_SC_DC EC_IOW(0x2b, ec_ioctl_config_t) -#define EC_IOCTL_SC_SDO EC_IOW(0x2c, ec_ioctl_sc_sdo_t) -#define EC_IOCTL_SC_SDO_REQUEST EC_IOWR(0x2d, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SC_VOE EC_IOWR(0x2e, ec_ioctl_voe_t) -#define EC_IOCTL_SC_STATE EC_IOWR(0x2f, ec_ioctl_sc_state_t) -#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x20) -#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x31) -#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x32) -#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x33, ec_ioctl_domain_state_t) -#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x34, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x35, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x36, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x37, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x38, ec_ioctl_sdo_request_t) -#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x39, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x3a, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_READ EC_IOW(0x3b, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x3c, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_WRITE EC_IOWR(0x3d, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_EXEC EC_IOWR(0x3e, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_DATA EC_IOWR(0x3f, ec_ioctl_voe_t) +#define EC_IOCTL_SYNC_MON_QUEUE EC_IO(0x24) +#define EC_IOCTL_SYNC_MON_PROCESS EC_IOR(0x25, uint32_t) +#define EC_IOCTL_SC_SYNC EC_IOW(0x26, ec_ioctl_config_t) +#define EC_IOCTL_SC_WATCHDOG EC_IOW(0x27, ec_ioctl_config_t) +#define EC_IOCTL_SC_ADD_PDO EC_IOW(0x28, ec_ioctl_config_pdo_t) +#define EC_IOCTL_SC_CLEAR_PDOS EC_IOW(0x29, ec_ioctl_config_pdo_t) +#define EC_IOCTL_SC_ADD_ENTRY EC_IOW(0x2a, ec_ioctl_add_pdo_entry_t) +#define EC_IOCTL_SC_CLEAR_ENTRIES EC_IOW(0x2b, ec_ioctl_config_pdo_t) +#define EC_IOCTL_SC_REG_PDO_ENTRY EC_IOWR(0x2c, ec_ioctl_reg_pdo_entry_t) +#define EC_IOCTL_SC_DC EC_IOW(0x2d, ec_ioctl_config_t) +#define EC_IOCTL_SC_SDO EC_IOW(0x2e, ec_ioctl_sc_sdo_t) +#define EC_IOCTL_SC_SDO_REQUEST EC_IOWR(0x2f, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SC_VOE EC_IOWR(0x20, ec_ioctl_voe_t) +#define EC_IOCTL_SC_STATE EC_IOWR(0x31, ec_ioctl_sc_state_t) +#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x32) +#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x33) +#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x34) +#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x35, ec_ioctl_domain_state_t) +#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x36, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x37, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x38, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x39, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x3a, ec_ioctl_sdo_request_t) +#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x3b, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x3c, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_READ EC_IOW(0x3d, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x3e, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_WRITE EC_IOWR(0x3f, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_EXEC EC_IOWR(0x40, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_DATA EC_IOWR(0x41, ec_ioctl_voe_t) /*****************************************************************************/ diff -r 4844a8433915 -r 0c484ee12d89 master/master.c --- a/master/master.c Fri Aug 21 09:46:29 2009 +0200 +++ b/master/master.c Fri Aug 21 12:15:16 2009 +0200 @@ -227,12 +227,23 @@ EC_ERR("Failed to allocate synchronisation datagram.\n"); goto out_clear_ref_sync; } + + // init sync monitor datagram + ec_datagram_init(&master->sync_mon_datagram); + snprintf(master->sync_mon_datagram.name, EC_DATAGRAM_NAME_SIZE, "syncmon"); + ret = ec_datagram_brd(&master->sync_mon_datagram, 0x092c, 4); + if (ret < 0) { + ec_datagram_clear(&master->sync_mon_datagram); + EC_ERR("Failed to allocate sync monitoring datagram.\n"); + goto out_clear_sync; + } + ec_master_find_dc_ref_clock(master); // init character device ret = ec_cdev_init(&master->cdev, master, device_number); if (ret) - goto out_clear_sync; + goto out_clear_sync_mon; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) master->class_device = device_create(class, NULL, @@ -261,6 +272,8 @@ out_clear_cdev: ec_cdev_clear(&master->cdev); +out_clear_sync_mon: + ec_datagram_clear(&master->sync_mon_datagram); out_clear_sync: ec_datagram_clear(&master->sync_datagram); out_clear_ref_sync: @@ -299,6 +312,7 @@ ec_master_clear_slave_configs(master); ec_master_clear_slaves(master); + ec_datagram_clear(&master->sync_mon_datagram); ec_datagram_clear(&master->sync_datagram); ec_datagram_clear(&master->ref_sync_datagram); ec_fsm_master_clear(&master->fsm); @@ -1924,6 +1938,25 @@ /*****************************************************************************/ +void ecrt_master_sync_monitor_queue(ec_master_t *master) +{ + ec_datagram_zero(&master->sync_mon_datagram); + ec_master_queue_datagram(master, &master->sync_mon_datagram); +} + +/*****************************************************************************/ + +uint32_t ecrt_master_sync_monitor_process(ec_master_t *master) +{ + if (master->sync_mon_datagram.state == EC_DATAGRAM_RECEIVED) { + return EC_READ_U32(master->sync_mon_datagram.data) & 0x7fffffff; + } else { + return 0xffffffff; + } +} + +/*****************************************************************************/ + /** \cond */ EXPORT_SYMBOL(ecrt_master_create_domain); @@ -1938,6 +1971,8 @@ EXPORT_SYMBOL(ecrt_master_application_time); EXPORT_SYMBOL(ecrt_master_sync_reference_clock); EXPORT_SYMBOL(ecrt_master_sync_slave_clocks); +EXPORT_SYMBOL(ecrt_master_sync_monitor_queue); +EXPORT_SYMBOL(ecrt_master_sync_monitor_process); /** \endcond */ diff -r 4844a8433915 -r 0c484ee12d89 master/master.h --- a/master/master.h Fri Aug 21 09:46:29 2009 +0200 +++ b/master/master.h Fri Aug 21 12:15:16 2009 +0200 @@ -126,6 +126,8 @@ reference clock to the master clock. */ ec_datagram_t sync_datagram; /**< Datagram used for DC drift compensation. */ + ec_datagram_t sync_mon_datagram; /**< Datagram used for DC synchronisation + monitoring. */ ec_slave_t *dc_ref_clock; /**< DC reference clock slave. */ unsigned int scan_busy; /**< Current scan state. */