mirror of
https://gitlab.com/etherlab.org/ethercat.git
synced 2026-02-05 19:39:50 +08:00
Added interface to select the reference clock and to sync to it.
Added rtai_rtdm_dc example, thanks to Graeme Foot.
This commit is contained in:
@@ -102,6 +102,8 @@ examples/rtai/Makefile
|
||||
examples/rtai/Makefile.in
|
||||
examples/rtai_rtdm/.libs
|
||||
examples/rtai_rtdm/ec_rtai_rtdm_example
|
||||
examples/rtai_rtdm_dc/.libs
|
||||
examples/rtai_rtdm_dc/ec_rtai_rtdm_dc_example
|
||||
examples/user/.deps
|
||||
examples/user/.libs
|
||||
examples/user/Makefile
|
||||
|
||||
@@ -804,6 +804,7 @@ AC_CONFIG_FILES([
|
||||
examples/rtai/Kbuild
|
||||
examples/rtai/Makefile
|
||||
examples/rtai_rtdm/Makefile
|
||||
examples/rtai_rtdm_dc/Makefile
|
||||
examples/tty/Kbuild
|
||||
examples/tty/Makefile
|
||||
examples/user/Makefile
|
||||
|
||||
@@ -49,7 +49,8 @@ endif
|
||||
|
||||
if ENABLE_RTAI
|
||||
SUBDIRS += \
|
||||
rtai_rtdm
|
||||
rtai_rtdm \
|
||||
rtai_rtdm_dc
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -59,6 +60,7 @@ DIST_SUBDIRS = \
|
||||
mini \
|
||||
rtai \
|
||||
rtai_rtdm \
|
||||
rtai_rtdm_dc \
|
||||
tty \
|
||||
user \
|
||||
xenomai \
|
||||
|
||||
43
examples/rtai_rtdm_dc/Makefile.am
Normal file
43
examples/rtai_rtdm_dc/Makefile.am
Normal file
@@ -0,0 +1,43 @@
|
||||
#------------------------------------------------------------------------------
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
# Copyright (C) 2006-2012 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
|
||||
#
|
||||
# ---
|
||||
#
|
||||
# The license mentioned above concerns the source code only. Using the
|
||||
# EtherCAT technology and brand is only permitted in compliance with the
|
||||
# industrial property and similar rights of Beckhoff Automation GmbH.
|
||||
#
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
noinst_PROGRAMS = ec_rtai_rtdm_dc_example
|
||||
|
||||
ec_rtai_rtdm_dc_example_SOURCES = main.c
|
||||
|
||||
ec_rtai_rtdm_dc_example_CFLAGS = \
|
||||
-Wall \
|
||||
-I$(top_srcdir)/include \
|
||||
$(RTAI_LXRT_CFLAGS)
|
||||
|
||||
ec_rtai_rtdm_dc_example_LDFLAGS = \
|
||||
$(RTAI_LXRT_LDFLAGS) -llxrt -lrtdm \
|
||||
-L$(top_builddir)/lib/.libs -lethercat_rtdm
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
547
examples/rtai_rtdm_dc/main.c
Normal file
547
examples/rtai_rtdm_dc/main.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -57,6 +57,13 @@
|
||||
* ecrt_reg_request_data(), ecrt_reg_request_state(),
|
||||
* ecrt_reg_request_write(), ecrt_reg_request_read() and the feature flag
|
||||
* EC_HAVE_REG_ACCESS.
|
||||
* - Added method to select the reference clock,
|
||||
* ecrt_master_select_reference_clock() and the feature flag
|
||||
* EC_HAVE_SELECT_REF_CLOCK to check, if the method is available.
|
||||
* - Added method to get the reference clock time,
|
||||
* ecrt_master_reference_clock_time() and the feature flag
|
||||
* EC_HAVE_REF_CLOCK_TIME to have the possibility to synchronize the master
|
||||
* clock to the reference clock.
|
||||
*
|
||||
* Changes in version 1.5:
|
||||
*
|
||||
@@ -163,6 +170,14 @@
|
||||
*/
|
||||
#define EC_HAVE_REG_ACCESS
|
||||
|
||||
/* Defined if the method ecrt_master_select_reference_clock() is available.
|
||||
*/
|
||||
#define EC_HAVE_SELECT_REF_CLOCK
|
||||
|
||||
/* Defined if the method ecrt_master_reference_clock_time() is available.
|
||||
*/
|
||||
#define EC_HAVE_REF_CLOCK_TIME
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** End of list marker.
|
||||
@@ -664,6 +679,20 @@ ec_slave_config_t *ecrt_master_slave_config(
|
||||
uint32_t product_code /**< Expected product code. */
|
||||
);
|
||||
|
||||
/** Selects the reference clock for distributed clocks.
|
||||
*
|
||||
* If this method is not called for a certain master, or if the slave
|
||||
* configuration pointer is NULL, then the first slave with DC functionality
|
||||
* will provide the reference clock.
|
||||
*
|
||||
* \return 0 on success, otherwise negative error code.
|
||||
*/
|
||||
int ecrt_master_select_reference_clock(
|
||||
ec_master_t *master, /**< EtherCAT master. */
|
||||
ec_slave_config_t *sc /**< Slave config of the slave to use as the
|
||||
* reference slave (or NULL). */
|
||||
);
|
||||
|
||||
/** Obtains master information.
|
||||
*
|
||||
* No memory is allocated on the heap in
|
||||
@@ -989,6 +1018,27 @@ void ecrt_master_sync_slave_clocks(
|
||||
ec_master_t *master /**< EtherCAT master. */
|
||||
);
|
||||
|
||||
/** Get the lower 32 bit of the reference clock system time.
|
||||
*
|
||||
* This method can be used to synchronize the master to the reference clock.
|
||||
*
|
||||
* The reference clock system time is queried via the
|
||||
* ecrt_master_sync_slave_clocks() method, that reads the system time of the
|
||||
* reference clock and writes it to the slave clocks (so be sure to call it
|
||||
* cyclically to get valid data).
|
||||
*
|
||||
* \attention The returned time is the system time of the reference clock
|
||||
* minus the transmission delay of the reference clock.
|
||||
*
|
||||
* \retval 0 success, system time was written into \a time.
|
||||
* \retval -ENXIO No reference clock found.
|
||||
* \retval -EIO Slave synchronization datagram was not received.
|
||||
*/
|
||||
int ecrt_master_reference_clock_time(
|
||||
ec_master_t *master, /**< EtherCAT master. */
|
||||
uint32_t *time /**< Pointer to store the queried system time. */
|
||||
);
|
||||
|
||||
/** Queues the DC synchrony monitoring datagram for sending.
|
||||
*
|
||||
* The datagram broadcast-reads all "System time difference" registers (\a
|
||||
|
||||
40
lib/master.c
40
lib/master.c
@@ -200,6 +200,31 @@ ec_slave_config_t *ecrt_master_slave_config(ec_master_t *master,
|
||||
return sc;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int ecrt_master_select_reference_clock(ec_master_t *master,
|
||||
ec_slave_config_t *sc)
|
||||
{
|
||||
uint32_t config_index;
|
||||
int ret;
|
||||
|
||||
if (sc) {
|
||||
config_index = sc->index;
|
||||
}
|
||||
else {
|
||||
config_index = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
ret = ioctl(master->fd, EC_IOCTL_SELECT_REF_CLOCK, config_index);
|
||||
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||
fprintf(stderr, "Failed to select reference clock: %s\n",
|
||||
strerror(EC_IOCTL_ERRNO(ret)));
|
||||
return -EC_IOCTL_ERRNO(ret);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
int ecrt_master(ec_master_t *master, ec_master_info_t *master_info)
|
||||
@@ -681,6 +706,21 @@ void ecrt_master_sync_slave_clocks(ec_master_t *master)
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int ecrt_master_reference_clock_time(ec_master_t *master, uint32_t *time)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ioctl(master->fd, EC_IOCTL_REF_CLOCK_TIME, time);
|
||||
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||
fprintf(stderr, "Failed to get reference clock time: %s\n",
|
||||
strerror(EC_IOCTL_ERRNO(ret)));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
void ecrt_master_sync_monitor_queue(ec_master_t *master)
|
||||
|
||||
@@ -1562,6 +1562,45 @@ static int ec_ioctl_create_slave_config(
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Select the DC reference clock.
|
||||
*/
|
||||
static int ec_ioctl_select_ref_clock(
|
||||
ec_master_t *master, /**< EtherCAT master. */
|
||||
void *arg, /**< ioctl() argument. */
|
||||
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
|
||||
)
|
||||
{
|
||||
uint32_t config_index = (uint32_t) arg;
|
||||
ec_slave_config_t *sc = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if (unlikely(!ctx->requested)) {
|
||||
ret = -EPERM;
|
||||
goto out_return;
|
||||
}
|
||||
|
||||
if (down_interruptible(&master->master_sem)) {
|
||||
ret = -EINTR;
|
||||
goto out_return;
|
||||
}
|
||||
|
||||
if (config_index != 0xFFFFFFFF) {
|
||||
if (!(sc = ec_master_get_config(master, config_index))) {
|
||||
ret = -ENOENT;
|
||||
goto out_up;
|
||||
}
|
||||
}
|
||||
|
||||
ecrt_master_select_reference_clock(master, sc);
|
||||
|
||||
out_up:
|
||||
up(&master->master_sem);
|
||||
out_return:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Activates the master.
|
||||
*/
|
||||
static int ec_ioctl_activate(
|
||||
@@ -1842,6 +1881,35 @@ static int ec_ioctl_sync_slaves(
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Get the system time of the reference clock.
|
||||
*/
|
||||
static int ec_ioctl_ref_clock_time(
|
||||
ec_master_t *master, /**< EtherCAT master. */
|
||||
void *arg, /**< ioctl() argument. */
|
||||
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
|
||||
)
|
||||
{
|
||||
uint32_t time;
|
||||
int ret;
|
||||
|
||||
if (unlikely(!ctx->requested)) {
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
ret = ecrt_master_reference_clock_time(master, &time);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (copy_to_user((void __user *) arg, &time, sizeof(time))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Queue the sync monitoring datagram.
|
||||
*/
|
||||
static int ec_ioctl_sync_mon_queue(
|
||||
@@ -3923,6 +3991,13 @@ long EC_IOCTL(ec_master_t *master, ec_ioctl_context_t *ctx,
|
||||
}
|
||||
ret = ec_ioctl_create_slave_config(master, arg, ctx);
|
||||
break;
|
||||
case EC_IOCTL_SELECT_REF_CLOCK:
|
||||
if (!ctx->writable) {
|
||||
ret = -EPERM;
|
||||
break;
|
||||
}
|
||||
ret = ec_ioctl_select_ref_clock(master, arg, ctx);
|
||||
break;
|
||||
case EC_IOCTL_ACTIVATE:
|
||||
if (!ctx->writable) {
|
||||
ret = -EPERM;
|
||||
@@ -3978,6 +4053,13 @@ long EC_IOCTL(ec_master_t *master, ec_ioctl_context_t *ctx,
|
||||
}
|
||||
ret = ec_ioctl_sync_slaves(master, arg, ctx);
|
||||
break;
|
||||
case EC_IOCTL_REF_CLOCK_TIME:
|
||||
if (!ctx->writable) {
|
||||
ret = -EPERM;
|
||||
break;
|
||||
}
|
||||
ret = ec_ioctl_ref_clock_time(master, arg, ctx);
|
||||
break;
|
||||
case EC_IOCTL_SYNC_MON_QUEUE:
|
||||
if (!ctx->writable) {
|
||||
ret = -EPERM;
|
||||
|
||||
112
master/ioctl.h
112
master/ioctl.h
@@ -56,7 +56,7 @@
|
||||
*
|
||||
* Increment this when changing the ioctl interface!
|
||||
*/
|
||||
#define EC_IOCTL_VERSION_MAGIC 22
|
||||
#define EC_IOCTL_VERSION_MAGIC 23
|
||||
|
||||
// Command-line tool
|
||||
#define EC_IOCTL_MODULE EC_IOR(0x00, ec_ioctl_module_t)
|
||||
@@ -96,58 +96,60 @@
|
||||
#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_ACTIVATE EC_IOR(0x21, ec_ioctl_master_activate_t)
|
||||
#define EC_IOCTL_DEACTIVATE EC_IO(0x22)
|
||||
#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_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(0x30, 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_EMERG_SIZE EC_IOW(0x36, ec_ioctl_sc_emerg_t)
|
||||
#define EC_IOCTL_SC_EMERG_POP EC_IOWR(0x37, ec_ioctl_sc_emerg_t)
|
||||
#define EC_IOCTL_SC_EMERG_CLEAR EC_IOW(0x38, ec_ioctl_sc_emerg_t)
|
||||
#define EC_IOCTL_SC_EMERG_OVERRUNS EC_IOWR(0x39, ec_ioctl_sc_emerg_t)
|
||||
#define EC_IOCTL_SC_SDO_REQUEST EC_IOWR(0x3a, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SC_REG_REQUEST EC_IOWR(0x3b, ec_ioctl_reg_request_t)
|
||||
#define EC_IOCTL_SC_VOE EC_IOWR(0x3c, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_SC_STATE EC_IOWR(0x3d, ec_ioctl_sc_state_t)
|
||||
#define EC_IOCTL_SC_IDN EC_IOW(0x3e, ec_ioctl_sc_idn_t)
|
||||
#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x3f)
|
||||
#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x40)
|
||||
#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x41)
|
||||
#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x42, ec_ioctl_domain_state_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_INDEX EC_IOWR(0x43, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x44, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x45, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x46, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x47, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x48, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_REG_REQUEST_DATA EC_IOWR(0x49, ec_ioctl_reg_request_t)
|
||||
#define EC_IOCTL_REG_REQUEST_STATE EC_IOWR(0x4a, ec_ioctl_reg_request_t)
|
||||
#define EC_IOCTL_REG_REQUEST_WRITE EC_IOWR(0x4b, ec_ioctl_reg_request_t)
|
||||
#define EC_IOCTL_REG_REQUEST_READ EC_IOWR(0x4c, ec_ioctl_reg_request_t)
|
||||
#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x4d, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x4e, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_READ EC_IOW(0x4f, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x50, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_WRITE EC_IOWR(0x51, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_EXEC EC_IOWR(0x52, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_DATA EC_IOWR(0x53, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x54, size_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, ec_ioctl_app_time_t)
|
||||
#define EC_IOCTL_SYNC_REF EC_IO(0x29)
|
||||
#define EC_IOCTL_SYNC_SLAVES EC_IO(0x2a)
|
||||
#define EC_IOCTL_REF_CLOCK_TIME EC_IOR(0x2b, uint32_t)
|
||||
#define EC_IOCTL_SYNC_MON_QUEUE EC_IO(0x2c)
|
||||
#define EC_IOCTL_SYNC_MON_PROCESS EC_IOR(0x2d, uint32_t)
|
||||
#define EC_IOCTL_RESET EC_IO(0x2e)
|
||||
#define EC_IOCTL_SC_SYNC EC_IOW(0x2f, ec_ioctl_config_t)
|
||||
#define EC_IOCTL_SC_WATCHDOG EC_IOW(0x30, ec_ioctl_config_t)
|
||||
#define EC_IOCTL_SC_ADD_PDO EC_IOW(0x31, ec_ioctl_config_pdo_t)
|
||||
#define EC_IOCTL_SC_CLEAR_PDOS EC_IOW(0x32, ec_ioctl_config_pdo_t)
|
||||
#define EC_IOCTL_SC_ADD_ENTRY EC_IOW(0x33, ec_ioctl_add_pdo_entry_t)
|
||||
#define EC_IOCTL_SC_CLEAR_ENTRIES EC_IOW(0x34, ec_ioctl_config_pdo_t)
|
||||
#define EC_IOCTL_SC_REG_PDO_ENTRY EC_IOWR(0x35, ec_ioctl_reg_pdo_entry_t)
|
||||
#define EC_IOCTL_SC_DC EC_IOW(0x36, ec_ioctl_config_t)
|
||||
#define EC_IOCTL_SC_SDO EC_IOW(0x37, ec_ioctl_sc_sdo_t)
|
||||
#define EC_IOCTL_SC_EMERG_SIZE EC_IOW(0x38, ec_ioctl_sc_emerg_t)
|
||||
#define EC_IOCTL_SC_EMERG_POP EC_IOWR(0x39, ec_ioctl_sc_emerg_t)
|
||||
#define EC_IOCTL_SC_EMERG_CLEAR EC_IOW(0x3a, ec_ioctl_sc_emerg_t)
|
||||
#define EC_IOCTL_SC_EMERG_OVERRUNS EC_IOWR(0x3b, ec_ioctl_sc_emerg_t)
|
||||
#define EC_IOCTL_SC_SDO_REQUEST EC_IOWR(0x3c, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SC_REG_REQUEST EC_IOWR(0x3d, ec_ioctl_reg_request_t)
|
||||
#define EC_IOCTL_SC_VOE EC_IOWR(0x3e, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_SC_STATE EC_IOWR(0x3f, ec_ioctl_sc_state_t)
|
||||
#define EC_IOCTL_SC_IDN EC_IOW(0x40, ec_ioctl_sc_idn_t)
|
||||
#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x41)
|
||||
#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x42)
|
||||
#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x43)
|
||||
#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x44, ec_ioctl_domain_state_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_INDEX EC_IOWR(0x45, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x46, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x47, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x48, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x49, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x4a, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_REG_REQUEST_DATA EC_IOWR(0x4b, ec_ioctl_reg_request_t)
|
||||
#define EC_IOCTL_REG_REQUEST_STATE EC_IOWR(0x4c, ec_ioctl_reg_request_t)
|
||||
#define EC_IOCTL_REG_REQUEST_WRITE EC_IOWR(0x4d, ec_ioctl_reg_request_t)
|
||||
#define EC_IOCTL_REG_REQUEST_READ EC_IOWR(0x4e, ec_ioctl_reg_request_t)
|
||||
#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x4f, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x50, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_READ EC_IOW(0x51, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x52, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_WRITE EC_IOWR(0x53, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_EXEC EC_IOWR(0x54, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_DATA EC_IOWR(0x55, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x56, size_t)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@@ -748,12 +750,12 @@ typedef struct {
|
||||
} ec_ioctl_context_t;
|
||||
|
||||
long ec_ioctl(ec_master_t *, ec_ioctl_context_t *, unsigned int,
|
||||
void __user *);
|
||||
void __user *);
|
||||
|
||||
#ifdef EC_RTDM
|
||||
|
||||
long ec_ioctl_rtdm(ec_master_t *, ec_ioctl_context_t *, unsigned int,
|
||||
void __user *);
|
||||
void __user *);
|
||||
int ec_rtdm_mmap(ec_ioctl_context_t *, void **);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -234,7 +234,7 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT master */
|
||||
ec_datagram_init(&master->ref_sync_datagram);
|
||||
snprintf(master->ref_sync_datagram.name, EC_DATAGRAM_NAME_SIZE,
|
||||
"refsync");
|
||||
ret = ec_datagram_apwr(&master->ref_sync_datagram, 0, 0x0910, 8);
|
||||
ret = ec_datagram_prealloc(&master->ref_sync_datagram, 4);
|
||||
if (ret < 0) {
|
||||
ec_datagram_clear(&master->ref_sync_datagram);
|
||||
EC_MASTER_ERR(master, "Failed to allocate reference"
|
||||
@@ -265,7 +265,8 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT master */
|
||||
goto out_clear_sync;
|
||||
}
|
||||
|
||||
ec_master_find_dc_ref_clock(master);
|
||||
master->dc_ref_config = NULL;
|
||||
master->dc_ref_clock = NULL;
|
||||
|
||||
// init character device
|
||||
ret = ec_cdev_init(&master->cdev, master, device_number);
|
||||
@@ -395,6 +396,8 @@ void ec_master_clear_slave_configs(ec_master_t *master)
|
||||
{
|
||||
ec_slave_config_t *sc, *next;
|
||||
|
||||
master->dc_ref_config = NULL;
|
||||
|
||||
list_for_each_entry_safe(sc, next, &master->configs, list) {
|
||||
list_del(&sc->list);
|
||||
ec_slave_config_clear(sc);
|
||||
@@ -1872,18 +1875,52 @@ void ec_master_find_dc_ref_clock(
|
||||
{
|
||||
ec_slave_t *slave, *ref = NULL;
|
||||
|
||||
for (slave = master->slaves;
|
||||
slave < master->slaves + master->slave_count;
|
||||
slave++) {
|
||||
if (slave->base_dc_supported && slave->has_dc_system_time) {
|
||||
ref = slave;
|
||||
break;
|
||||
if (master->dc_ref_config) {
|
||||
// Use application-selected reference clock
|
||||
slave = master->dc_ref_config->slave;
|
||||
|
||||
if (slave) {
|
||||
if (slave->base_dc_supported && slave->has_dc_system_time) {
|
||||
ref = slave;
|
||||
}
|
||||
else {
|
||||
EC_MASTER_WARN(master, "Slave %u can not act as a"
|
||||
" DC reference clock!", slave->ring_position);
|
||||
}
|
||||
}
|
||||
else {
|
||||
EC_MASTER_WARN(master, "DC reference clock config (%u-%u)"
|
||||
" has no slave attached!\n", master->dc_ref_config->alias,
|
||||
master->dc_ref_config->position);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Use first slave with DC support as reference clock
|
||||
for (slave = master->slaves;
|
||||
slave < master->slaves + master->slave_count;
|
||||
slave++) {
|
||||
if (slave->base_dc_supported && slave->has_dc_system_time) {
|
||||
ref = slave;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
master->dc_ref_clock = ref;
|
||||
|
||||
// This call always succeeds, because the datagram has been pre-allocated.
|
||||
if (ref) {
|
||||
EC_MASTER_INFO(master, "Using slave %u as DC reference clock.\n",
|
||||
ref->ring_position);
|
||||
}
|
||||
else {
|
||||
EC_MASTER_INFO(master, "No DC reference clock found.\n");
|
||||
}
|
||||
|
||||
// These calls always succeed, because the
|
||||
// datagrams have been pre-allocated.
|
||||
ec_datagram_fpwr(&master->ref_sync_datagram,
|
||||
ref ? ref->station_address : 0xffff, 0x0910, 4);
|
||||
ec_datagram_frmw(&master->sync_datagram,
|
||||
ref ? ref->station_address : 0xffff, 0x0910, 4);
|
||||
}
|
||||
@@ -2392,6 +2429,26 @@ ec_slave_config_t *ecrt_master_slave_config(ec_master_t *master,
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int ecrt_master_select_reference_clock(ec_master_t *master,
|
||||
ec_slave_config_t *sc)
|
||||
{
|
||||
if (sc) {
|
||||
ec_slave_t *slave = sc->slave;
|
||||
|
||||
// output an early warning
|
||||
if (slave &&
|
||||
(!slave->base_dc_supported || !slave->has_dc_system_time)) {
|
||||
EC_MASTER_WARN(master, "Slave %u can not act as"
|
||||
" a reference clock!", slave->ring_position);
|
||||
}
|
||||
}
|
||||
|
||||
master->dc_ref_config = sc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int ecrt_master(ec_master_t *master, ec_master_info_t *master_info)
|
||||
{
|
||||
EC_MASTER_DBG(master, 1, "ecrt_master(master = 0x%p,"
|
||||
@@ -2525,6 +2582,25 @@ void ecrt_master_application_time(ec_master_t *master, uint64_t app_time)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int ecrt_master_reference_clock_time(ec_master_t *master, uint32_t *time)
|
||||
{
|
||||
if (!master->dc_ref_clock) {
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
if (master->sync_datagram.state != EC_DATAGRAM_RECEIVED) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
// Get returned datagram time, transmission delay removed.
|
||||
*time = EC_READ_U32(master->sync_datagram.data) -
|
||||
master->dc_ref_clock->transmission_delay;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ecrt_master_sync_reference_clock(ec_master_t *master)
|
||||
{
|
||||
EC_WRITE_U32(master->ref_sync_datagram.data, master->app_time);
|
||||
@@ -2985,11 +3061,13 @@ EXPORT_SYMBOL(ecrt_master_callbacks);
|
||||
EXPORT_SYMBOL(ecrt_master);
|
||||
EXPORT_SYMBOL(ecrt_master_get_slave);
|
||||
EXPORT_SYMBOL(ecrt_master_slave_config);
|
||||
EXPORT_SYMBOL(ecrt_master_select_reference_clock);
|
||||
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);
|
||||
EXPORT_SYMBOL(ecrt_master_reference_clock_time);
|
||||
EXPORT_SYMBOL(ecrt_master_sync_monitor_queue);
|
||||
EXPORT_SYMBOL(ecrt_master_sync_monitor_process);
|
||||
EXPORT_SYMBOL(ecrt_master_sdo_download);
|
||||
|
||||
@@ -224,6 +224,8 @@ struct ec_master {
|
||||
compensation. */
|
||||
ec_datagram_t sync_mon_datagram; /**< Datagram used for DC synchronisation
|
||||
monitoring. */
|
||||
ec_slave_config_t *dc_ref_config; /**< Application-selected DC reference
|
||||
clock slave config. */
|
||||
ec_slave_t *dc_ref_clock; /**< DC reference clock slave. */
|
||||
|
||||
unsigned int scan_busy; /**< Current scan state. */
|
||||
|
||||
Reference in New Issue
Block a user