diff --git a/include/ecrt.h b/include/ecrt.h
index c306278f..6f9eece2 100644
--- a/include/ecrt.h
+++ b/include/ecrt.h
@@ -187,6 +187,10 @@
*/
#define EC_HAVE_REG_BY_POS
+/** Defined if the method ecrt_master_sync_reference_clock_to() is available.
+ */
+#define EC_HAVE_SYNC_TO
+
/*****************************************************************************/
/** End of list marker.
@@ -1018,11 +1022,10 @@ int ecrt_master_link_state(
* distributed clocks. The time is not incremented by the master itself, so
* this method has to be called cyclically.
*
- * \attention The first call of this method is used to calculate the phase
- * delay for the slaves' SYNC0/1 interrupts. Either the method has to be
- * called during the realtime cycle *only*, or the first time submitted must
- * be in-phase with the realtime cycle. Otherwise synchronisation problems can
- * occur.
+ * \attention The time passed to this method is used to calculate the phase of
+ * the slaves' SYNC0/1 interrupts. It should be called constantly at the same
+ * point of the realtime cycle. So it is recommended to call it at the start
+ * of the calculations to avoid deviancies due to changing execution times.
*
* The time is used when setting the slaves' System Time Offset and
* Cyclic Operation Start Time registers and when synchronizing the
@@ -1030,7 +1033,8 @@ int ecrt_master_link_state(
* ecrt_master_sync_reference_clock().
*
* The time is defined as nanoseconds from 2000-01-01 00:00. Converting an
- * epoch time can be done with the EC_TIMEVAL2NANO() macro.
+ * epoch time can be done with the EC_TIMEVAL2NANO() macro, but is not
+ * necessary, since the absolute value is not of any interest.
*/
void ecrt_master_application_time(
ec_master_t *master, /**< EtherCAT master. */
@@ -1046,6 +1050,16 @@ void ecrt_master_sync_reference_clock(
ec_master_t *master /**< EtherCAT master. */
);
+/** Queues the DC reference clock drift compensation datagram for sending.
+ *
+ * The reference clock will by synchronized to the time passed in the
+ * sync_time parameter.
+ */
+void ecrt_master_sync_reference_clock_to(
+ ec_master_t *master, /**< EtherCAT master. */
+ uint64_t sync_time /**< Sync reference clock to this time. */
+ );
+
/** Queues the DC clock drift compensation datagram for sending.
*
* All slave clocks synchronized to the reference clock.
diff --git a/lib/master.c b/lib/master.c
index 7c218428..709a7ba8 100644
--- a/lib/master.c
+++ b/lib/master.c
@@ -672,12 +672,12 @@ int ecrt_master_link_state(const ec_master_t *master, unsigned int dev_idx,
void ecrt_master_application_time(ec_master_t *master, uint64_t app_time)
{
- ec_ioctl_app_time_t data;
+ uint64_t time;
int ret;
- data.app_time = app_time;
+ time = app_time;
- ret = ioctl(master->fd, EC_IOCTL_APP_TIME, &data);
+ ret = ioctl(master->fd, EC_IOCTL_APP_TIME, &time);
if (EC_IOCTL_IS_ERROR(ret)) {
fprintf(stderr, "Failed to set application time: %s\n",
strerror(EC_IOCTL_ERRNO(ret)));
@@ -699,6 +699,23 @@ void ecrt_master_sync_reference_clock(ec_master_t *master)
/****************************************************************************/
+void ecrt_master_sync_reference_clock_to(ec_master_t *master,
+ uint64_t sync_time)
+{
+ uint64_t time;
+ int ret;
+
+ time = sync_time;
+
+ ret = ioctl(master->fd, EC_IOCTL_SYNC_REF_TO, &time);
+ if (EC_IOCTL_IS_ERROR(ret)) {
+ fprintf(stderr, "Failed to sync reference clock: %s\n",
+ strerror(EC_IOCTL_ERRNO(ret)));
+ }
+}
+
+/****************************************************************************/
+
void ecrt_master_sync_slave_clocks(ec_master_t *master)
{
int ret;
diff --git a/master/ioctl.c b/master/ioctl.c
index 8f0b091e..065f3249 100755
--- a/master/ioctl.c
+++ b/master/ioctl.c
@@ -2015,16 +2015,16 @@ static ATTRIBUTES int ec_ioctl_app_time(
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
)
{
- ec_ioctl_app_time_t data;
+ uint64_t time;
if (unlikely(!ctx->requested))
return -EPERM;
- if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
+ if (copy_from_user(&time, (void __user *) arg, sizeof(time))) {
return -EFAULT;
}
- ecrt_master_application_time(master, data.app_time);
+ ecrt_master_application_time(master, time);
return 0;
}
@@ -2050,6 +2050,31 @@ static ATTRIBUTES int ec_ioctl_sync_ref(
/*****************************************************************************/
+/** Sync the reference clock.
+ *
+ * \return Zero on success, otherwise a negative error code.
+ */
+static ATTRIBUTES int ec_ioctl_sync_ref_to(
+ ec_master_t *master, /**< EtherCAT master. */
+ void *arg, /**< ioctl() argument. */
+ ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
+ )
+{
+ uint64_t time;
+
+ if (unlikely(!ctx->requested))
+ return -EPERM;
+
+ if (copy_from_user(&time, (void __user *) arg, sizeof(time))) {
+ return -EFAULT;
+ }
+
+ ecrt_master_sync_reference_clock_to(master, time);
+ return 0;
+}
+
+/*****************************************************************************/
+
/** Sync the slave clocks.
*
* \return Zero on success, otherwise a negative error code.
@@ -4448,6 +4473,13 @@ long EC_IOCTL(
}
ret = ec_ioctl_sync_ref(master, arg, ctx);
break;
+ case EC_IOCTL_SYNC_REF_TO:
+ if (!ctx->writable) {
+ ret = -EPERM;
+ break;
+ }
+ ret = ec_ioctl_sync_ref_to(master, arg, ctx);
+ break;
case EC_IOCTL_SYNC_SLAVES:
if (!ctx->writable) {
ret = -EPERM;
diff --git a/master/ioctl.h b/master/ioctl.h
index a78a4e86..dad17d1a 100644
--- a/master/ioctl.h
+++ b/master/ioctl.h
@@ -104,56 +104,57 @@
#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, ec_ioctl_app_time_t)
+#define EC_IOCTL_APP_TIME EC_IOW(0x29, uint64_t)
#define EC_IOCTL_SYNC_REF EC_IO(0x2a)
-#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_SC_OVERLAPPING_IO EC_IOW(0x5a, ec_ioctl_config_t)
+#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)
/*****************************************************************************/
@@ -784,13 +785,6 @@ typedef struct {
/*****************************************************************************/
-typedef struct {
- // inputs
- uint64_t app_time;
-} ec_ioctl_app_time_t;
-
-/*****************************************************************************/
-
#ifdef __KERNEL__
/** Context data structure for file handles.
diff --git a/master/master.c b/master/master.c
index 7bfb4366..ae04ac59 100644
--- a/master/master.c
+++ b/master/master.c
@@ -2820,6 +2820,19 @@ void ecrt_master_sync_reference_clock(ec_master_t *master)
/*****************************************************************************/
+void ecrt_master_sync_reference_clock_to(
+ ec_master_t *master,
+ uint64_t sync_time
+ )
+{
+ if (master->dc_ref_clock) {
+ EC_WRITE_U32(master->ref_sync_datagram.data, sync_time);
+ ec_master_queue_datagram(master, &master->ref_sync_datagram);
+ }
+}
+
+/*****************************************************************************/
+
void ecrt_master_sync_slave_clocks(ec_master_t *master)
{
if (master->dc_ref_clock) {
@@ -3292,6 +3305,7 @@ 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_reference_clock_to);
EXPORT_SYMBOL(ecrt_master_sync_slave_clocks);
EXPORT_SYMBOL(ecrt_master_reference_clock_time);
EXPORT_SYMBOL(ecrt_master_sync_monitor_queue);