Re-worked and seamlessly integrated RTDM interface.
This commit is contained in:
parent
592c2a8cea
commit
9faaa83212
|
|
@ -100,12 +100,18 @@ examples/modules.order
|
||||||
examples/rtai/Kbuild
|
examples/rtai/Kbuild
|
||||||
examples/rtai/Makefile
|
examples/rtai/Makefile
|
||||||
examples/rtai/Makefile.in
|
examples/rtai/Makefile.in
|
||||||
|
examples/rtai_rtdm/.libs
|
||||||
|
examples/rtai_rtdm/ec_rtai_rtdm_example
|
||||||
examples/user/.deps
|
examples/user/.deps
|
||||||
examples/user/.libs
|
examples/user/.libs
|
||||||
examples/user/Makefile
|
examples/user/Makefile
|
||||||
examples/user/Makefile.in
|
examples/user/Makefile.in
|
||||||
examples/user/TAGS
|
examples/user/TAGS
|
||||||
examples/user/ec_user_example
|
examples/user/ec_user_example
|
||||||
|
examples/xenomai/.libs
|
||||||
|
examples/xenomai/ec_xenomai_example
|
||||||
|
examples/xenomai_posix/.libs
|
||||||
|
examples/xenomai_posix/ec_xenomai_posix_example
|
||||||
include/Makefile
|
include/Makefile
|
||||||
include/Makefile.in
|
include/Makefile.in
|
||||||
include/TAGS
|
include/TAGS
|
||||||
|
|
@ -115,6 +121,7 @@ lib/Makefile
|
||||||
lib/Makefile.in
|
lib/Makefile.in
|
||||||
lib/TAGS
|
lib/TAGS
|
||||||
lib/libethercat.la
|
lib/libethercat.la
|
||||||
|
lib/libethercat_rtdm.la
|
||||||
libtool
|
libtool
|
||||||
m4/Makefile
|
m4/Makefile
|
||||||
m4/Makefile.in
|
m4/Makefile.in
|
||||||
|
|
|
||||||
1
FEATURES
1
FEATURES
|
|
@ -27,6 +27,7 @@ General Features:
|
||||||
|
|
||||||
* Supports any realtime environment through independent architecture.
|
* Supports any realtime environment through independent architecture.
|
||||||
- RTAI, Xenomai, RT-Preempt, etc.
|
- RTAI, Xenomai, RT-Preempt, etc.
|
||||||
|
- RTDM Interface for userspace realtime enviroments
|
||||||
- Operation possible without any realtime extension at all.
|
- Operation possible without any realtime extension at all.
|
||||||
|
|
||||||
* Common API for Realtime-Applications in kernel- and userspace.
|
* Common API for Realtime-Applications in kernel- and userspace.
|
||||||
|
|
|
||||||
97
configure.ac
97
configure.ac
|
|
@ -426,13 +426,15 @@ AC_SUBST(KERNEL_R8169,[$kernel_r8169])
|
||||||
AC_ARG_WITH([rtai-dir],
|
AC_ARG_WITH([rtai-dir],
|
||||||
AC_HELP_STRING(
|
AC_HELP_STRING(
|
||||||
[--with-rtai-dir=<DIR>],
|
[--with-rtai-dir=<DIR>],
|
||||||
[RTAI path (only for RTAI examples)]
|
[RTAI path, for RTDM interface and RTAI examples]
|
||||||
),
|
),
|
||||||
[
|
[
|
||||||
rtaidir=[$withval]
|
rtaidir=[$withval]
|
||||||
|
rtai=1
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
rtaidir=""
|
rtaidir=""
|
||||||
|
rtai=0
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -445,9 +447,99 @@ else
|
||||||
AC_MSG_ERROR([no RTAI installation found in ${rtaidir}!])
|
AC_MSG_ERROR([no RTAI installation found in ${rtaidir}!])
|
||||||
fi
|
fi
|
||||||
AC_MSG_RESULT([$rtaidir])
|
AC_MSG_RESULT([$rtaidir])
|
||||||
|
|
||||||
|
rtai_lxrt_cflags=`$rtaidir/bin/rtai-config --lxrt-cflags`
|
||||||
|
rtai_lxrt_ldflags=`$rtaidir/bin/rtai-config --lxrt-ldflags`
|
||||||
fi
|
fi
|
||||||
|
|
||||||
AC_SUBST(RTAI_DIR,[$rtaidir])
|
AC_SUBST(RTAI_DIR,[$rtaidir])
|
||||||
|
AM_CONDITIONAL(ENABLE_RTAI, test "x$rtai" = "x1")
|
||||||
|
AC_SUBST(ENABLE_RTAI,[$rtai])
|
||||||
|
|
||||||
|
AC_SUBST(RTAI_LXRT_CFLAGS,[$rtai_lxrt_cflags])
|
||||||
|
AC_SUBST(RTAI_LXRT_LDFLAGS,[$rtai_lxrt_ldflags])
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# Xenomai path (optional)
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
AC_ARG_WITH([xenomai-dir],
|
||||||
|
AC_HELP_STRING(
|
||||||
|
[--with-xenomai-dir=<DIR>],
|
||||||
|
[Xenomai path, for RTDM interface and Xenomai examples]
|
||||||
|
),
|
||||||
|
[
|
||||||
|
xenomaidir=[$withval]
|
||||||
|
xeno=1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
xenomaidir=""
|
||||||
|
xeno=0
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([for Xenomai path])
|
||||||
|
|
||||||
|
if test -z "${xenomaidir}"; then
|
||||||
|
AC_MSG_RESULT([not specified.])
|
||||||
|
else
|
||||||
|
if test \! -r ${xenomaidir}/include/xeno_config.h; then
|
||||||
|
AC_MSG_ERROR([no Xenomai installation found in ${xenomaidir}!])
|
||||||
|
fi
|
||||||
|
AC_MSG_RESULT([$xenomaidir])
|
||||||
|
|
||||||
|
xeno_native_cflags=`$xenomaidir/bin/xeno-config --skin native --cflags`
|
||||||
|
xeno_native_ldflags=`$xenomaidir/bin/xeno-config --skin native --ldflags`
|
||||||
|
xeno_posix_cflags=`$xenomaidir/bin/xeno-config --skin posix --cflags`
|
||||||
|
xeno_posix_ldflags=`$xenomaidir/bin/xeno-config --skin posix --ldflags`
|
||||||
|
xeno_rtdm_cflags=`$xenomaidir/bin/xeno-config --skin rtdm --cflags`
|
||||||
|
xeno_rtdm_ldflags=`$xenomaidir/bin/xeno-config --skin rtdm --ldflags`
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_SUBST(XENOMAI_DIR,[$xenomaidir])
|
||||||
|
AM_CONDITIONAL(ENABLE_XENOMAI, test "x$xeno" = "x1")
|
||||||
|
AC_SUBST(ENABLE_XENOMAI,[$xeno])
|
||||||
|
|
||||||
|
AC_SUBST(XENOMAI_NATIVE_CFLAGS,[$xeno_native_cflags])
|
||||||
|
AC_SUBST(XENOMAI_NATIVE_LDFLAGS,[$xeno_native_ldflags])
|
||||||
|
AC_SUBST(XENOMAI_POSIX_CFLAGS,[$xeno_posix_cflags])
|
||||||
|
AC_SUBST(XENOMAI_POSIX_LDFLAGS,[$xeno_posix_ldflags])
|
||||||
|
AC_SUBST(XENOMAI_RTDM_CFLAGS,[$xeno_rtdm_cflags])
|
||||||
|
AC_SUBST(XENOMAI_RTDM_LDFLAGS,[$xeno_rtdm_ldflags])
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# RTDM interface (optional)
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
AC_ARG_ENABLE([rtdm],
|
||||||
|
AC_HELP_STRING(
|
||||||
|
[--enable-rtdm],
|
||||||
|
[Enable RTDM interface, depends on RTAI or Xenomai]
|
||||||
|
),
|
||||||
|
[
|
||||||
|
case "${enableval}" in
|
||||||
|
yes) rtdm=1
|
||||||
|
;;
|
||||||
|
no) rtdm=0
|
||||||
|
;;
|
||||||
|
*) AC_MSG_ERROR([Invalid value for --enable-rtdm])
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
],
|
||||||
|
[rtdm=0]
|
||||||
|
)
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([whether to build RTDM interface])
|
||||||
|
|
||||||
|
if test "x${rtdm}" = "x1"; then
|
||||||
|
AC_DEFINE([EC_RTDM], [1], [RTDM interface enabled])
|
||||||
|
AC_MSG_RESULT([yes])
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
fi
|
||||||
|
|
||||||
|
AM_CONDITIONAL(ENABLE_RTDM, test "x$rtdm" = "x1")
|
||||||
|
AC_SUBST(ENABLE_RTDM,[$rtdm])
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
# Debug interface
|
# Debug interface
|
||||||
|
|
@ -711,9 +803,12 @@ AC_CONFIG_FILES([
|
||||||
examples/mini/Makefile
|
examples/mini/Makefile
|
||||||
examples/rtai/Kbuild
|
examples/rtai/Kbuild
|
||||||
examples/rtai/Makefile
|
examples/rtai/Makefile
|
||||||
|
examples/rtai_rtdm/Makefile
|
||||||
examples/tty/Kbuild
|
examples/tty/Kbuild
|
||||||
examples/tty/Makefile
|
examples/tty/Makefile
|
||||||
examples/user/Makefile
|
examples/user/Makefile
|
||||||
|
examples/xenomai/Makefile
|
||||||
|
examples/xenomai_posix/Makefile
|
||||||
include/Makefile
|
include/Makefile
|
||||||
lib/Makefile
|
lib/Makefile
|
||||||
m4/Makefile
|
m4/Makefile
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
# $Id$
|
# $Id$
|
||||||
#
|
#
|
||||||
# Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
|
# Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||||
#
|
#
|
||||||
# This file is part of the IgH EtherCAT Master.
|
# This file is part of the IgH EtherCAT Master.
|
||||||
#
|
#
|
||||||
|
|
@ -35,4 +35,8 @@ ifeq (@ENABLE_TTY@,1)
|
||||||
obj-m += tty/
|
obj-m += tty/
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq (@ENABLE_RTAI@,1)
|
||||||
|
obj-m += rtai/ dc_rtai/
|
||||||
|
endif
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
# $Id$
|
# $Id$
|
||||||
#
|
#
|
||||||
# Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
|
# Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||||
#
|
#
|
||||||
# This file is part of the IgH EtherCAT Master.
|
# This file is part of the IgH EtherCAT Master.
|
||||||
#
|
#
|
||||||
|
|
@ -40,13 +40,29 @@ SUBDIRS += \
|
||||||
tty
|
tty
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if ENABLE_RTDM
|
||||||
|
if ENABLE_XENOMAI
|
||||||
|
SUBDIRS += \
|
||||||
|
xenomai \
|
||||||
|
xenomai_posix
|
||||||
|
endif
|
||||||
|
|
||||||
|
if ENABLE_RTAI
|
||||||
|
SUBDIRS += \
|
||||||
|
rtai_rtdm
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
DIST_SUBDIRS = \
|
DIST_SUBDIRS = \
|
||||||
dc_rtai \
|
dc_rtai \
|
||||||
dc_user \
|
dc_user \
|
||||||
mini \
|
mini \
|
||||||
rtai \
|
rtai \
|
||||||
|
rtai_rtdm \
|
||||||
tty \
|
tty \
|
||||||
user
|
user \
|
||||||
|
xenomai \
|
||||||
|
xenomai_posix
|
||||||
|
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
Kbuild.in
|
Kbuild.in
|
||||||
|
|
|
||||||
|
|
@ -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_example
|
||||||
|
|
||||||
|
ec_rtai_rtdm_example_SOURCES = main.c
|
||||||
|
|
||||||
|
ec_rtai_rtdm_example_CFLAGS = \
|
||||||
|
-Wall \
|
||||||
|
-I$(top_srcdir)/include \
|
||||||
|
$(RTAI_LXRT_CFLAGS)
|
||||||
|
|
||||||
|
ec_rtai_rtdm_example_LDFLAGS = \
|
||||||
|
$(RTAI_LXRT_LDFLAGS) -llxrt -lrtdm \
|
||||||
|
-L$(top_builddir)/lib/.libs -lethercat_rtdm
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
@ -0,0 +1,289 @@
|
||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2011 IgH Andreas Stewering-Bone
|
||||||
|
* 2012 Florian Pose <fp@igh-essen.com>
|
||||||
|
*
|
||||||
|
* 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* ---
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include <sched.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
#include <rtai_lxrt.h>
|
||||||
|
#include <rtdm/rtdm.h>
|
||||||
|
|
||||||
|
#include "ecrt.h"
|
||||||
|
|
||||||
|
#define rt_printf(X, Y)
|
||||||
|
|
||||||
|
#define NSEC_PER_SEC 1000000000
|
||||||
|
|
||||||
|
RT_TASK *task;
|
||||||
|
|
||||||
|
const static unsigned int cycle_us = 1000; /* 1 ms */
|
||||||
|
|
||||||
|
static int run = 1;
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
// EtherCAT
|
||||||
|
static ec_master_t *master = NULL;
|
||||||
|
static ec_master_state_t master_state = {};
|
||||||
|
|
||||||
|
static ec_domain_t *domain1 = NULL;
|
||||||
|
static ec_domain_state_t domain1_state = {};
|
||||||
|
|
||||||
|
static uint8_t *domain1_pd = NULL;
|
||||||
|
|
||||||
|
static ec_slave_config_t *sc_dig_out_01 = NULL;
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
// process data
|
||||||
|
|
||||||
|
#define BusCoupler01_Pos 0, 0
|
||||||
|
#define DigOutSlave01_Pos 0, 1
|
||||||
|
|
||||||
|
#define Beckhoff_EK1100 0x00000002, 0x044c2c52
|
||||||
|
#define Beckhoff_EL2004 0x00000002, 0x07d43052
|
||||||
|
|
||||||
|
// offsets for PDO entries
|
||||||
|
static unsigned int off_dig_out0 = 0;
|
||||||
|
|
||||||
|
// process data
|
||||||
|
|
||||||
|
const static ec_pdo_entry_reg_t domain1_regs[] = {
|
||||||
|
{DigOutSlave01_Pos, Beckhoff_EL2004, 0x7000, 0x01, &off_dig_out0, NULL},
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Slave 1, "EL2004"
|
||||||
|
* Vendor ID: 0x00000002
|
||||||
|
* Product code: 0x07d43052
|
||||||
|
* Revision number: 0x00100000
|
||||||
|
*/
|
||||||
|
|
||||||
|
ec_pdo_entry_info_t slave_1_pdo_entries[] = {
|
||||||
|
{0x7000, 0x01, 1}, /* Output */
|
||||||
|
{0x7010, 0x01, 1}, /* Output */
|
||||||
|
{0x7020, 0x01, 1}, /* Output */
|
||||||
|
{0x7030, 0x01, 1}, /* Output */
|
||||||
|
};
|
||||||
|
|
||||||
|
ec_pdo_info_t slave_1_pdos[] = {
|
||||||
|
{0x1600, 1, slave_1_pdo_entries + 0}, /* Channel 1 */
|
||||||
|
{0x1601, 1, slave_1_pdo_entries + 1}, /* Channel 2 */
|
||||||
|
{0x1602, 1, slave_1_pdo_entries + 2}, /* Channel 3 */
|
||||||
|
{0x1603, 1, slave_1_pdo_entries + 3}, /* Channel 4 */
|
||||||
|
};
|
||||||
|
|
||||||
|
ec_sync_info_t slave_1_syncs[] = {
|
||||||
|
{0, EC_DIR_OUTPUT, 4, slave_1_pdos + 0, EC_WD_ENABLE},
|
||||||
|
{0xff}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Realtime task
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
void rt_check_domain_state(void)
|
||||||
|
{
|
||||||
|
ec_domain_state_t ds = {};
|
||||||
|
|
||||||
|
ecrt_domain_state(domain1, &ds);
|
||||||
|
|
||||||
|
if (ds.working_counter != domain1_state.working_counter) {
|
||||||
|
rt_printf("Domain1: WC %u.\n", ds.working_counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ds.wc_state != domain1_state.wc_state) {
|
||||||
|
rt_printf("Domain1: State %u.\n", ds.wc_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
domain1_state = ds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
void rt_check_master_state(void)
|
||||||
|
{
|
||||||
|
ec_master_state_t ms;
|
||||||
|
|
||||||
|
ecrt_master_state(master, &ms);
|
||||||
|
|
||||||
|
if (ms.slaves_responding != master_state.slaves_responding) {
|
||||||
|
rt_printf("%u slave(s).\n", ms.slaves_responding);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ms.al_states != master_state.al_states) {
|
||||||
|
rt_printf("AL states: 0x%02X.\n", ms.al_states);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ms.link_up != master_state.link_up) {
|
||||||
|
rt_printf("Link is %s.\n", ms.link_up ? "up" : "down");
|
||||||
|
}
|
||||||
|
|
||||||
|
master_state = ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
void my_cyclic(void)
|
||||||
|
{
|
||||||
|
int cycle_counter = 0;
|
||||||
|
int period;
|
||||||
|
unsigned int blink = 0;
|
||||||
|
|
||||||
|
rt_set_periodic_mode();
|
||||||
|
period = (int) nano2count((RTIME) cycle_us * 1000);
|
||||||
|
start_rt_timer(period);
|
||||||
|
rt_make_hard_real_time();
|
||||||
|
rt_task_make_periodic(task, rt_get_time() + 10 * period, period);
|
||||||
|
|
||||||
|
while (run) {
|
||||||
|
rt_task_wait_period();
|
||||||
|
|
||||||
|
cycle_counter++;
|
||||||
|
|
||||||
|
// receive EtherCAT
|
||||||
|
ecrt_master_receive(master);
|
||||||
|
ecrt_domain_process(domain1);
|
||||||
|
|
||||||
|
rt_check_domain_state();
|
||||||
|
|
||||||
|
if (!(cycle_counter % 1000)) {
|
||||||
|
rt_check_master_state();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(cycle_counter % 200)) {
|
||||||
|
blink = !blink;
|
||||||
|
}
|
||||||
|
|
||||||
|
EC_WRITE_U8(domain1_pd + off_dig_out0, blink ? 0x00 : 0x0F);
|
||||||
|
|
||||||
|
// send process data
|
||||||
|
ecrt_domain_queue(domain1);
|
||||||
|
ecrt_master_send(master);
|
||||||
|
}
|
||||||
|
|
||||||
|
rt_make_soft_real_time();
|
||||||
|
stop_rt_timer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Signal handler
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
void signal_handler(int sig)
|
||||||
|
{
|
||||||
|
run = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Main function
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
ec_slave_config_t *sc;
|
||||||
|
|
||||||
|
signal(SIGTERM, signal_handler);
|
||||||
|
signal(SIGINT, signal_handler);
|
||||||
|
|
||||||
|
mlockall(MCL_CURRENT | MCL_FUTURE);
|
||||||
|
|
||||||
|
printf("Requesting master...\n");
|
||||||
|
master = ecrt_request_master(0);
|
||||||
|
if (!master) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
domain1 = ecrt_master_create_domain(master);
|
||||||
|
if (!domain1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Creating slave configurations...\n");
|
||||||
|
|
||||||
|
// Create configuration for bus coupler
|
||||||
|
sc = ecrt_master_slave_config(master, BusCoupler01_Pos, Beckhoff_EK1100);
|
||||||
|
if (!sc) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sc_dig_out_01 =
|
||||||
|
ecrt_master_slave_config(master, DigOutSlave01_Pos, Beckhoff_EL2004);
|
||||||
|
if (!sc_dig_out_01) {
|
||||||
|
fprintf(stderr, "Failed to get slave configuration.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ecrt_slave_config_pdos(sc_dig_out_01, EC_END, slave_1_syncs)) {
|
||||||
|
fprintf(stderr, "Failed to configure PDOs.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ecrt_domain_reg_pdo_entry_list(domain1, domain1_regs)) {
|
||||||
|
fprintf(stderr, "PDO entry registration failed!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Activating master...\n");
|
||||||
|
if (ecrt_master_activate(master)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(domain1_pd = ecrt_domain_data(domain1))) {
|
||||||
|
fprintf(stderr, "Failed to get domain data pointer.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create cyclic RT-thread */
|
||||||
|
struct sched_param param;
|
||||||
|
param.sched_priority = sched_get_priority_max(SCHED_FIFO) - 1;
|
||||||
|
if (sched_setscheduler(0, SCHED_FIFO, ¶m) == -1) {
|
||||||
|
puts("ERROR IN SETTING THE SCHEDULER");
|
||||||
|
perror("errno");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
task = rt_task_init(nam2num("ec_rtai_rtdm_example"),
|
||||||
|
0 /* priority */, 0 /* stack size */, 0 /* msg size */);
|
||||||
|
|
||||||
|
my_cyclic();
|
||||||
|
|
||||||
|
rt_task_delete(task);
|
||||||
|
|
||||||
|
printf("End of Program\n");
|
||||||
|
ecrt_release_master(master);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# $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_xenomai_example
|
||||||
|
|
||||||
|
ec_xenomai_example_SOURCES = main.c
|
||||||
|
|
||||||
|
ec_xenomai_example_CFLAGS = \
|
||||||
|
-Wall \
|
||||||
|
-I$(top_srcdir)/include \
|
||||||
|
$(XENOMAI_NATIVE_CFLAGS) \
|
||||||
|
$(XENOMAI_RTDM_CFLAGS)
|
||||||
|
|
||||||
|
ec_xenomai_example_LDFLAGS = \
|
||||||
|
-L$(top_builddir)/lib/.libs -lethercat_rtdm \
|
||||||
|
$(XENOMAI_NATIVE_LDFLAGS) \
|
||||||
|
$(XENOMAI_RTDM_LDFLAGS)
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
@ -0,0 +1,292 @@
|
||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009-2010 Moehwald GmbH B. Benner
|
||||||
|
* 2011 IgH Andreas Stewering-Bone
|
||||||
|
* 2012 Florian Pose <fp@igh-essen.com>
|
||||||
|
*
|
||||||
|
* 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* ---
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <rtdm/rtdm.h>
|
||||||
|
#include <native/task.h>
|
||||||
|
#include <native/sem.h>
|
||||||
|
#include <native/mutex.h>
|
||||||
|
#include <native/timer.h>
|
||||||
|
#include <rtdk.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include "ecrt.h"
|
||||||
|
|
||||||
|
RT_TASK my_task;
|
||||||
|
|
||||||
|
static int run = 1;
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
// EtherCAT
|
||||||
|
static ec_master_t *master = NULL;
|
||||||
|
static ec_master_state_t master_state = {};
|
||||||
|
|
||||||
|
static ec_domain_t *domain1 = NULL;
|
||||||
|
static ec_domain_state_t domain1_state = {};
|
||||||
|
|
||||||
|
static uint8_t *domain1_pd = NULL;
|
||||||
|
|
||||||
|
static ec_slave_config_t *sc_dig_out_01 = NULL;
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
// process data
|
||||||
|
|
||||||
|
#define BusCoupler01_Pos 0, 0
|
||||||
|
#define DigOutSlave01_Pos 0, 1
|
||||||
|
|
||||||
|
#define Beckhoff_EK1100 0x00000002, 0x044c2c52
|
||||||
|
#define Beckhoff_EL2004 0x00000002, 0x07d43052
|
||||||
|
|
||||||
|
// offsets for PDO entries
|
||||||
|
static unsigned int off_dig_out0 = 0;
|
||||||
|
|
||||||
|
// process data
|
||||||
|
|
||||||
|
const static ec_pdo_entry_reg_t domain1_regs[] = {
|
||||||
|
{DigOutSlave01_Pos, Beckhoff_EL2004, 0x7000, 0x01, &off_dig_out0, NULL},
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Slave 1, "EL2004"
|
||||||
|
* Vendor ID: 0x00000002
|
||||||
|
* Product code: 0x07d43052
|
||||||
|
* Revision number: 0x00100000
|
||||||
|
*/
|
||||||
|
|
||||||
|
ec_pdo_entry_info_t slave_1_pdo_entries[] = {
|
||||||
|
{0x7000, 0x01, 1}, /* Output */
|
||||||
|
{0x7010, 0x01, 1}, /* Output */
|
||||||
|
{0x7020, 0x01, 1}, /* Output */
|
||||||
|
{0x7030, 0x01, 1}, /* Output */
|
||||||
|
};
|
||||||
|
|
||||||
|
ec_pdo_info_t slave_1_pdos[] = {
|
||||||
|
{0x1600, 1, slave_1_pdo_entries + 0}, /* Channel 1 */
|
||||||
|
{0x1601, 1, slave_1_pdo_entries + 1}, /* Channel 2 */
|
||||||
|
{0x1602, 1, slave_1_pdo_entries + 2}, /* Channel 3 */
|
||||||
|
{0x1603, 1, slave_1_pdo_entries + 3}, /* Channel 4 */
|
||||||
|
};
|
||||||
|
|
||||||
|
ec_sync_info_t slave_1_syncs[] = {
|
||||||
|
{0, EC_DIR_OUTPUT, 4, slave_1_pdos + 0, EC_WD_ENABLE},
|
||||||
|
{0xff}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Realtime task
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
void rt_check_domain_state(void)
|
||||||
|
{
|
||||||
|
ec_domain_state_t ds = {};
|
||||||
|
|
||||||
|
ecrt_domain_state(domain1, &ds);
|
||||||
|
|
||||||
|
if (ds.working_counter != domain1_state.working_counter) {
|
||||||
|
rt_printf("Domain1: WC %u.\n", ds.working_counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ds.wc_state != domain1_state.wc_state) {
|
||||||
|
rt_printf("Domain1: State %u.\n", ds.wc_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
domain1_state = ds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
void rt_check_master_state(void)
|
||||||
|
{
|
||||||
|
ec_master_state_t ms;
|
||||||
|
|
||||||
|
ecrt_master_state(master, &ms);
|
||||||
|
|
||||||
|
if (ms.slaves_responding != master_state.slaves_responding) {
|
||||||
|
rt_printf("%u slave(s).\n", ms.slaves_responding);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ms.al_states != master_state.al_states) {
|
||||||
|
rt_printf("AL states: 0x%02X.\n", ms.al_states);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ms.link_up != master_state.link_up) {
|
||||||
|
rt_printf("Link is %s.\n", ms.link_up ? "up" : "down");
|
||||||
|
}
|
||||||
|
|
||||||
|
master_state = ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
void my_task_proc(void *arg)
|
||||||
|
{
|
||||||
|
int cycle_counter = 0;
|
||||||
|
unsigned int blink = 0;
|
||||||
|
|
||||||
|
rt_task_set_periodic(NULL, TM_NOW, 1000000); // ns
|
||||||
|
|
||||||
|
while (run) {
|
||||||
|
rt_task_wait_period(NULL);
|
||||||
|
|
||||||
|
cycle_counter++;
|
||||||
|
|
||||||
|
// receive EtherCAT frames
|
||||||
|
ecrt_master_receive(master);
|
||||||
|
ecrt_domain_process(domain1);
|
||||||
|
|
||||||
|
rt_check_domain_state();
|
||||||
|
|
||||||
|
if (!(cycle_counter % 1000)) {
|
||||||
|
rt_check_master_state();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(cycle_counter % 200)) {
|
||||||
|
blink = !blink;
|
||||||
|
}
|
||||||
|
|
||||||
|
EC_WRITE_U8(domain1_pd + off_dig_out0, blink ? 0x0 : 0x0F);
|
||||||
|
|
||||||
|
// send process data
|
||||||
|
ecrt_domain_queue(domain1);
|
||||||
|
ecrt_master_send(master);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Signal handler
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
void signal_handler(int sig)
|
||||||
|
{
|
||||||
|
run = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Main function
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
ec_slave_config_t *sc;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Perform auto-init of rt_print buffers if the task doesn't do so */
|
||||||
|
rt_print_auto_init(1);
|
||||||
|
|
||||||
|
signal(SIGTERM, signal_handler);
|
||||||
|
signal(SIGINT, signal_handler);
|
||||||
|
|
||||||
|
mlockall(MCL_CURRENT | MCL_FUTURE);
|
||||||
|
|
||||||
|
printf("Requesting master...\n");
|
||||||
|
master = ecrt_request_master(0);
|
||||||
|
if (!master) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
domain1 = ecrt_master_create_domain(master);
|
||||||
|
if (!domain1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Creating slave configurations...\n");
|
||||||
|
|
||||||
|
// Create configuration for bus coupler
|
||||||
|
sc = ecrt_master_slave_config(master, BusCoupler01_Pos, Beckhoff_EK1100);
|
||||||
|
if (!sc) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sc_dig_out_01 =
|
||||||
|
ecrt_master_slave_config(master, DigOutSlave01_Pos, Beckhoff_EL2004);
|
||||||
|
if (!sc_dig_out_01) {
|
||||||
|
fprintf(stderr, "Failed to get slave configuration.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ecrt_slave_config_pdos(sc_dig_out_01, EC_END, slave_1_syncs)) {
|
||||||
|
fprintf(stderr, "Failed to configure PDOs.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ecrt_domain_reg_pdo_entry_list(domain1, domain1_regs)) {
|
||||||
|
fprintf(stderr, "PDO entry registration failed!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Activating master...\n");
|
||||||
|
if (ecrt_master_activate(master)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(domain1_pd = ecrt_domain_data(domain1))) {
|
||||||
|
fprintf(stderr, "Failed to get domain data pointer.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = rt_task_create(&my_task, "my_task", 0, 80, T_FPU);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Failed to create task: %s\n", strerror(-ret));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Starting my_task...\n");
|
||||||
|
ret = rt_task_start(&my_task, &my_task_proc, NULL);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Failed to start task: %s\n", strerror(-ret));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (run) {
|
||||||
|
sched_yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Deleting realtime task...\n");
|
||||||
|
rt_task_delete(&my_task);
|
||||||
|
|
||||||
|
printf("End of Program\n");
|
||||||
|
ecrt_release_master(master);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# $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_xenomai_posix_example
|
||||||
|
|
||||||
|
ec_xenomai_posix_example_SOURCES = main.c
|
||||||
|
|
||||||
|
ec_xenomai_posix_example_CFLAGS = \
|
||||||
|
-Wall \
|
||||||
|
-I$(top_srcdir)/include \
|
||||||
|
$(XENOMAI_POSIX_CFLAGS) \
|
||||||
|
$(XENOMAI_RTDM_CFLAGS)
|
||||||
|
|
||||||
|
ec_xenomai_posix_example_LDFLAGS = \
|
||||||
|
-L$(top_builddir)/lib/.libs -lethercat_rtdm \
|
||||||
|
$(XENOMAI_POSIX_LDFLAGS) \
|
||||||
|
$(XENOMAI_RTDM_LDFLAGS)
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
@ -0,0 +1,303 @@
|
||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2011 IgH Andreas Stewering-Bone
|
||||||
|
* 2012 Florian Pose <fp@igh-essen.com>
|
||||||
|
*
|
||||||
|
* 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* ---
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <mqueue.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <rtdm/rtdm.h>
|
||||||
|
#include <rtdk.h>
|
||||||
|
|
||||||
|
#include "ecrt.h"
|
||||||
|
|
||||||
|
#define NSEC_PER_SEC 1000000000
|
||||||
|
|
||||||
|
static unsigned int cycle_us = 1000; /* 1 ms */
|
||||||
|
|
||||||
|
static pthread_t cyclic_thread;
|
||||||
|
|
||||||
|
static int run = 1;
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
// EtherCAT
|
||||||
|
static ec_master_t *master = NULL;
|
||||||
|
static ec_master_state_t master_state = {};
|
||||||
|
|
||||||
|
static ec_domain_t *domain1 = NULL;
|
||||||
|
static ec_domain_state_t domain1_state = {};
|
||||||
|
|
||||||
|
static uint8_t *domain1_pd = NULL;
|
||||||
|
|
||||||
|
static ec_slave_config_t *sc_dig_out_01 = NULL;
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
// process data
|
||||||
|
|
||||||
|
#define BusCoupler01_Pos 0, 0
|
||||||
|
#define DigOutSlave01_Pos 0, 1
|
||||||
|
|
||||||
|
#define Beckhoff_EK1100 0x00000002, 0x044c2c52
|
||||||
|
#define Beckhoff_EL2004 0x00000002, 0x07d43052
|
||||||
|
|
||||||
|
// offsets for PDO entries
|
||||||
|
static unsigned int off_dig_out0 = 0;
|
||||||
|
|
||||||
|
// process data
|
||||||
|
|
||||||
|
const static ec_pdo_entry_reg_t domain1_regs[] = {
|
||||||
|
{DigOutSlave01_Pos, Beckhoff_EL2004, 0x7000, 0x01, &off_dig_out0, NULL},
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Slave 1, "EL2004"
|
||||||
|
* Vendor ID: 0x00000002
|
||||||
|
* Product code: 0x07d43052
|
||||||
|
* Revision number: 0x00100000
|
||||||
|
*/
|
||||||
|
|
||||||
|
ec_pdo_entry_info_t slave_1_pdo_entries[] = {
|
||||||
|
{0x7000, 0x01, 1}, /* Output */
|
||||||
|
{0x7010, 0x01, 1}, /* Output */
|
||||||
|
{0x7020, 0x01, 1}, /* Output */
|
||||||
|
{0x7030, 0x01, 1}, /* Output */
|
||||||
|
};
|
||||||
|
|
||||||
|
ec_pdo_info_t slave_1_pdos[] = {
|
||||||
|
{0x1600, 1, slave_1_pdo_entries + 0}, /* Channel 1 */
|
||||||
|
{0x1601, 1, slave_1_pdo_entries + 1}, /* Channel 2 */
|
||||||
|
{0x1602, 1, slave_1_pdo_entries + 2}, /* Channel 3 */
|
||||||
|
{0x1603, 1, slave_1_pdo_entries + 3}, /* Channel 4 */
|
||||||
|
};
|
||||||
|
|
||||||
|
ec_sync_info_t slave_1_syncs[] = {
|
||||||
|
{0, EC_DIR_OUTPUT, 4, slave_1_pdos + 0, EC_WD_ENABLE},
|
||||||
|
{0xff}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Realtime task
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
void rt_check_domain_state(void)
|
||||||
|
{
|
||||||
|
ec_domain_state_t ds = {};
|
||||||
|
|
||||||
|
ecrt_domain_state(domain1, &ds);
|
||||||
|
|
||||||
|
if (ds.working_counter != domain1_state.working_counter) {
|
||||||
|
rt_printf("Domain1: WC %u.\n", ds.working_counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ds.wc_state != domain1_state.wc_state) {
|
||||||
|
rt_printf("Domain1: State %u.\n", ds.wc_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
domain1_state = ds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
void rt_check_master_state(void)
|
||||||
|
{
|
||||||
|
ec_master_state_t ms;
|
||||||
|
|
||||||
|
ecrt_master_state(master, &ms);
|
||||||
|
|
||||||
|
if (ms.slaves_responding != master_state.slaves_responding) {
|
||||||
|
rt_printf("%u slave(s).\n", ms.slaves_responding);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ms.al_states != master_state.al_states) {
|
||||||
|
rt_printf("AL states: 0x%02X.\n", ms.al_states);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ms.link_up != master_state.link_up) {
|
||||||
|
rt_printf("Link is %s.\n", ms.link_up ? "up" : "down");
|
||||||
|
}
|
||||||
|
|
||||||
|
master_state = ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
void *my_thread(void *arg)
|
||||||
|
{
|
||||||
|
struct timespec next_period;
|
||||||
|
int cycle_counter = 0;
|
||||||
|
unsigned int blink = 0;
|
||||||
|
|
||||||
|
clock_gettime(CLOCK_REALTIME, &next_period);
|
||||||
|
|
||||||
|
while (run) {
|
||||||
|
next_period.tv_nsec += cycle_us * 1000;
|
||||||
|
while (next_period.tv_nsec >= NSEC_PER_SEC) {
|
||||||
|
next_period.tv_nsec -= NSEC_PER_SEC;
|
||||||
|
next_period.tv_sec++;
|
||||||
|
}
|
||||||
|
|
||||||
|
clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &next_period, NULL);
|
||||||
|
|
||||||
|
cycle_counter++;
|
||||||
|
|
||||||
|
// receive EtherCAT
|
||||||
|
ecrt_master_receive(master);
|
||||||
|
ecrt_domain_process(domain1);
|
||||||
|
|
||||||
|
rt_check_domain_state();
|
||||||
|
|
||||||
|
if (!(cycle_counter % 1000)) {
|
||||||
|
rt_check_master_state();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(cycle_counter % 200)) {
|
||||||
|
blink = !blink;
|
||||||
|
}
|
||||||
|
|
||||||
|
EC_WRITE_U8(domain1_pd + off_dig_out0, blink ? 0x0 : 0x0F);
|
||||||
|
|
||||||
|
// send process data
|
||||||
|
ecrt_domain_queue(domain1);
|
||||||
|
ecrt_master_send(master);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Signal handler
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
void signal_handler(int sig)
|
||||||
|
{
|
||||||
|
run = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Main function
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
ec_slave_config_t *sc;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
signal(SIGTERM, signal_handler);
|
||||||
|
signal(SIGINT, signal_handler);
|
||||||
|
|
||||||
|
mlockall(MCL_CURRENT | MCL_FUTURE);
|
||||||
|
|
||||||
|
printf("Requesting master...\n");
|
||||||
|
master = ecrt_request_master(0);
|
||||||
|
if (!master) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
domain1 = ecrt_master_create_domain(master);
|
||||||
|
if (!domain1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Creating slave configurations...\n");
|
||||||
|
|
||||||
|
// Create configuration for bus coupler
|
||||||
|
sc = ecrt_master_slave_config(master, BusCoupler01_Pos, Beckhoff_EK1100);
|
||||||
|
if (!sc) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sc_dig_out_01 =
|
||||||
|
ecrt_master_slave_config(master, DigOutSlave01_Pos, Beckhoff_EL2004);
|
||||||
|
if (!sc_dig_out_01) {
|
||||||
|
fprintf(stderr, "Failed to get slave configuration.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ecrt_slave_config_pdos(sc_dig_out_01, EC_END, slave_1_syncs)) {
|
||||||
|
fprintf(stderr, "Failed to configure PDOs.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ecrt_domain_reg_pdo_entry_list(domain1, domain1_regs)) {
|
||||||
|
fprintf(stderr, "PDO entry registration failed!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Activating master...\n");
|
||||||
|
if (ecrt_master_activate(master)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(domain1_pd = ecrt_domain_data(domain1))) {
|
||||||
|
fprintf(stderr, "Failed to get domain data pointer.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create cyclic RT-thread */
|
||||||
|
struct sched_param param = { .sched_priority = 82 };
|
||||||
|
|
||||||
|
pthread_attr_t thattr;
|
||||||
|
pthread_attr_init(&thattr);
|
||||||
|
pthread_attr_setdetachstate(&thattr, PTHREAD_CREATE_JOINABLE);
|
||||||
|
pthread_attr_setinheritsched(&thattr, PTHREAD_EXPLICIT_SCHED);
|
||||||
|
pthread_attr_setschedpolicy(&thattr, SCHED_FIFO);
|
||||||
|
pthread_setschedparam(cyclic_thread, SCHED_FIFO, ¶m);
|
||||||
|
|
||||||
|
ret = pthread_create(&cyclic_thread, &thattr, &my_thread, NULL);
|
||||||
|
if (ret) {
|
||||||
|
fprintf(stderr, "%s: pthread_create cyclic task failed\n",
|
||||||
|
strerror(-ret));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (run) {
|
||||||
|
sched_yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_join(cyclic_thread, NULL);
|
||||||
|
|
||||||
|
printf("End of Program\n");
|
||||||
|
ecrt_release_master(master);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
*
|
*
|
||||||
* $Id$
|
* $Id$
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
|
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||||
*
|
*
|
||||||
* This file is part of the IgH EtherCAT master userspace library.
|
* This file is part of the IgH EtherCAT master userspace library.
|
||||||
*
|
*
|
||||||
|
|
@ -781,7 +781,7 @@ int ecrt_master_sdo_upload(
|
||||||
* error occurred.
|
* error occurred.
|
||||||
*
|
*
|
||||||
* \retval 0 Success.
|
* \retval 0 Success.
|
||||||
* \retval -1 An error occured.
|
* \retval <0 Error code.
|
||||||
*/
|
*/
|
||||||
int ecrt_master_write_idn(
|
int ecrt_master_write_idn(
|
||||||
ec_master_t *master, /**< EtherCAT master. */
|
ec_master_t *master, /**< EtherCAT master. */
|
||||||
|
|
@ -800,7 +800,7 @@ int ecrt_master_write_idn(
|
||||||
* error occurred.
|
* error occurred.
|
||||||
*
|
*
|
||||||
* \retval 0 Success.
|
* \retval 0 Success.
|
||||||
* \retval -1 An error occured.
|
* \retval <0 Error code.
|
||||||
*/
|
*/
|
||||||
int ecrt_master_read_idn(
|
int ecrt_master_read_idn(
|
||||||
ec_master_t *master, /**< EtherCAT master. */
|
ec_master_t *master, /**< EtherCAT master. */
|
||||||
|
|
@ -848,6 +848,10 @@ void ecrt_master_deactivate(
|
||||||
);
|
);
|
||||||
|
|
||||||
/** Set interval between calls to ecrt_master_send().
|
/** Set interval between calls to ecrt_master_send().
|
||||||
|
*
|
||||||
|
* \retval 0 on success.
|
||||||
|
* \retval <0 Error code.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
int ecrt_master_set_send_interval(
|
int ecrt_master_set_send_interval(
|
||||||
ec_master_t *master, /**< EtherCAT master. */
|
ec_master_t *master, /**< EtherCAT master. */
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
# $Id$
|
# $Id$
|
||||||
#
|
#
|
||||||
# Copyright (C) 2006-2009 Florian Pose, Ingenieurgemeinschaft IgH
|
# Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||||
#
|
#
|
||||||
# This file is part of the IgH EtherCAT master userspace library.
|
# This file is part of the IgH EtherCAT master userspace library.
|
||||||
#
|
#
|
||||||
|
|
@ -32,8 +32,6 @@ lib_LTLIBRARIES = libethercat.la
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
libethercat_la_CFLAGS = -I$(srcdir)/.. -fno-strict-aliasing -Wall
|
|
||||||
libethercat_la_LDFLAGS = -version-info 1:0:0
|
|
||||||
libethercat_la_SOURCES = \
|
libethercat_la_SOURCES = \
|
||||||
common.c \
|
common.c \
|
||||||
domain.c \
|
domain.c \
|
||||||
|
|
@ -49,4 +47,29 @@ noinst_HEADERS = \
|
||||||
slave_config.h \
|
slave_config.h \
|
||||||
voe_handler.h
|
voe_handler.h
|
||||||
|
|
||||||
|
libethercat_la_CFLAGS = -fno-strict-aliasing -Wall
|
||||||
|
libethercat_la_LDFLAGS = -version-info 1:0:0
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
if ENABLE_RTDM
|
||||||
|
|
||||||
|
lib_LTLIBRARIES += libethercat_rtdm.la
|
||||||
|
|
||||||
|
libethercat_rtdm_la_SOURCES = $(libethercat_la_SOURCES)
|
||||||
|
libethercat_rtdm_la_CFLAGS = $(libethercat_la_CFLAGS) -DUSE_RTDM
|
||||||
|
libethercat_rtdm_la_LDFLAGS = $(libethercat_la_LDFLAGS)
|
||||||
|
|
||||||
|
if ENABLE_XENOMAI
|
||||||
|
libethercat_rtdm_la_CFLAGS += $(XENOMAI_RTDM_CFLAGS)
|
||||||
|
libethercat_rtdm_la_LDFLAGS += $(XENOMAI_RTDM_LDFLAGS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
if ENABLE_RTAI
|
||||||
|
libethercat_rtdm_la_CFLAGS += $(RTAI_LXRT_CFLAGS)
|
||||||
|
libethercat_rtdm_la_LDFLAGS += $(RTAI_LXRT_LDFLAGS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
|
|
|
||||||
29
lib/common.c
29
lib/common.c
|
|
@ -2,7 +2,7 @@
|
||||||
*
|
*
|
||||||
* $Id$
|
* $Id$
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006-2009 Florian Pose, Ingenieurgemeinschaft IgH
|
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||||
*
|
*
|
||||||
* This file is part of the IgH EtherCAT master userspace library.
|
* This file is part of the IgH EtherCAT master userspace library.
|
||||||
*
|
*
|
||||||
|
|
@ -33,15 +33,13 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#include "ioctl.h"
|
||||||
#include "master.h"
|
#include "master.h"
|
||||||
#include "master/ioctl.h"
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
@ -75,6 +73,7 @@ ec_master_t *ecrt_open_master(unsigned int master_index)
|
||||||
char path[MAX_PATH_LEN];
|
char path[MAX_PATH_LEN];
|
||||||
ec_master_t *master = NULL;
|
ec_master_t *master = NULL;
|
||||||
ec_ioctl_module_t module_data;
|
ec_ioctl_module_t module_data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
master = malloc(sizeof(ec_master_t));
|
master = malloc(sizeof(ec_master_t));
|
||||||
if (!master) {
|
if (!master) {
|
||||||
|
|
@ -87,17 +86,29 @@ ec_master_t *ecrt_open_master(unsigned int master_index)
|
||||||
master->first_domain = NULL;
|
master->first_domain = NULL;
|
||||||
master->first_config = NULL;
|
master->first_config = NULL;
|
||||||
|
|
||||||
snprintf(path, MAX_PATH_LEN - 1, "/dev/EtherCAT%u", master_index);
|
snprintf(path, MAX_PATH_LEN - 1,
|
||||||
|
#ifdef USE_RTDM
|
||||||
|
"EtherCAT%u",
|
||||||
|
#else
|
||||||
|
"/dev/EtherCAT%u",
|
||||||
|
#endif
|
||||||
|
master_index);
|
||||||
|
|
||||||
|
#ifdef USE_RTDM
|
||||||
|
master->fd = rt_dev_open(path, O_RDWR);
|
||||||
|
#else
|
||||||
master->fd = open(path, O_RDWR);
|
master->fd = open(path, O_RDWR);
|
||||||
if (master->fd == -1) {
|
#endif
|
||||||
fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno));
|
if (EC_IOCTL_IS_ERROR(master->fd)) {
|
||||||
|
fprintf(stderr, "Failed to open %s: %s\n", path,
|
||||||
|
strerror(EC_IOCTL_ERRNO(master->fd)));
|
||||||
goto out_clear;
|
goto out_clear;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ioctl(master->fd, EC_IOCTL_MODULE, &module_data) < 0) {
|
ret = ioctl(master->fd, EC_IOCTL_MODULE, &module_data);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to get module information from %s: %s\n",
|
fprintf(stderr, "Failed to get module information from %s: %s\n",
|
||||||
path, strerror(errno));
|
path, strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
goto out_clear;
|
goto out_clear;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
40
lib/domain.c
40
lib/domain.c
|
|
@ -2,7 +2,7 @@
|
||||||
*
|
*
|
||||||
* $Id$
|
* $Id$
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006-2009 Florian Pose, Ingenieurgemeinschaft IgH
|
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||||
*
|
*
|
||||||
* This file is part of the IgH EtherCAT master userspace library.
|
* This file is part of the IgH EtherCAT master userspace library.
|
||||||
*
|
*
|
||||||
|
|
@ -35,15 +35,13 @@
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <errno.h> /* ENOENT */
|
||||||
|
|
||||||
|
#include "ioctl.h"
|
||||||
#include "domain.h"
|
#include "domain.h"
|
||||||
#include "master.h"
|
#include "master.h"
|
||||||
#include "master/ioctl.h"
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
@ -64,11 +62,11 @@ int ecrt_domain_reg_pdo_entry_list(ec_domain_t *domain,
|
||||||
for (reg = regs; reg->index; reg++) {
|
for (reg = regs; reg->index; reg++) {
|
||||||
if (!(sc = ecrt_master_slave_config(domain->master, reg->alias,
|
if (!(sc = ecrt_master_slave_config(domain->master, reg->alias,
|
||||||
reg->position, reg->vendor_id, reg->product_code)))
|
reg->position, reg->vendor_id, reg->product_code)))
|
||||||
return -1; // FIXME
|
return -ENOENT;
|
||||||
|
|
||||||
if ((ret = ecrt_slave_config_reg_pdo_entry(sc, reg->index,
|
if ((ret = ecrt_slave_config_reg_pdo_entry(sc, reg->index,
|
||||||
reg->subindex, domain, reg->bit_position)) < 0)
|
reg->subindex, domain, reg->bit_position)) < 0)
|
||||||
return -1; // FIXME
|
return ret;
|
||||||
|
|
||||||
*reg->offset = ret;
|
*reg->offset = ret;
|
||||||
}
|
}
|
||||||
|
|
@ -85,9 +83,9 @@ uint8_t *ecrt_domain_data(ec_domain_t *domain)
|
||||||
|
|
||||||
offset = ioctl(domain->master->fd, EC_IOCTL_DOMAIN_OFFSET,
|
offset = ioctl(domain->master->fd, EC_IOCTL_DOMAIN_OFFSET,
|
||||||
domain->index);
|
domain->index);
|
||||||
if (offset == -1) {
|
if (EC_IOCTL_IS_ERROR(offset)) {
|
||||||
fprintf(stderr, "Failed to get domain offset: %s\n",
|
fprintf(stderr, "Failed to get domain offset: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(offset)));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -101,9 +99,12 @@ uint8_t *ecrt_domain_data(ec_domain_t *domain)
|
||||||
|
|
||||||
void ecrt_domain_process(ec_domain_t *domain)
|
void ecrt_domain_process(ec_domain_t *domain)
|
||||||
{
|
{
|
||||||
if (ioctl(domain->master->fd, EC_IOCTL_DOMAIN_PROCESS,
|
int ret;
|
||||||
domain->index) == -1) {
|
|
||||||
fprintf(stderr, "Failed to process domain: %s\n", strerror(errno));
|
ret = ioctl(domain->master->fd, EC_IOCTL_DOMAIN_PROCESS, domain->index);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
|
fprintf(stderr, "Failed to process domain: %s\n",
|
||||||
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -111,9 +112,12 @@ void ecrt_domain_process(ec_domain_t *domain)
|
||||||
|
|
||||||
void ecrt_domain_queue(ec_domain_t *domain)
|
void ecrt_domain_queue(ec_domain_t *domain)
|
||||||
{
|
{
|
||||||
if (ioctl(domain->master->fd, EC_IOCTL_DOMAIN_QUEUE,
|
int ret;
|
||||||
domain->index) == -1) {
|
|
||||||
fprintf(stderr, "Failed to queue domain: %s\n", strerror(errno));
|
ret = ioctl(domain->master->fd, EC_IOCTL_DOMAIN_QUEUE, domain->index);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
|
fprintf(stderr, "Failed to queue domain: %s\n",
|
||||||
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -122,13 +126,15 @@ void ecrt_domain_queue(ec_domain_t *domain)
|
||||||
void ecrt_domain_state(const ec_domain_t *domain, ec_domain_state_t *state)
|
void ecrt_domain_state(const ec_domain_t *domain, ec_domain_state_t *state)
|
||||||
{
|
{
|
||||||
ec_ioctl_domain_state_t data;
|
ec_ioctl_domain_state_t data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
data.domain_index = domain->index;
|
data.domain_index = domain->index;
|
||||||
data.state = state;
|
data.state = state;
|
||||||
|
|
||||||
if (ioctl(domain->master->fd, EC_IOCTL_DOMAIN_STATE, &data) == -1) {
|
ret = ioctl(domain->master->fd, EC_IOCTL_DOMAIN_STATE, &data);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to get domain state: %s\n",
|
fprintf(stderr, "Failed to get domain state: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||||
|
*
|
||||||
|
* This file is part of the IgH EtherCAT master userspace library.
|
||||||
|
*
|
||||||
|
* The IgH EtherCAT master userspace library is free software; you can
|
||||||
|
* redistribute it and/or modify it under the terms of the GNU Lesser General
|
||||||
|
* Public License as published by the Free Software Foundation; version 2.1
|
||||||
|
* of the License.
|
||||||
|
*
|
||||||
|
* The IgH EtherCAT master userspace library 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 Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with the IgH EtherCAT master userspace library. If not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* ---
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __EC_LIB_IOCTL_H__
|
||||||
|
#define __EC_LIB_IOCTL_H__
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
#ifdef USE_RTDM
|
||||||
|
#include <rtdm/rtdm.h>
|
||||||
|
#else
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
#include "master/ioctl.h"
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
#ifdef USE_RTDM
|
||||||
|
|
||||||
|
#define ioctl rt_dev_ioctl
|
||||||
|
|
||||||
|
/* rt_dev_ioctl() returns negative error code */
|
||||||
|
#define EC_IOCTL_IS_ERROR(X) ((X) < 0)
|
||||||
|
#define EC_IOCTL_ERRNO(X) (-(X))
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define ioctl ioctl
|
||||||
|
|
||||||
|
/* libc's ioctl() always returns -1 on error and sets errno */
|
||||||
|
#define EC_IOCTL_IS_ERROR(X) ((X) == -1)
|
||||||
|
#define EC_IOCTL_ERRNO(X) (errno)
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
#endif /* __EC_LIB_IOCTL_H__ */
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
245
lib/master.c
245
lib/master.c
|
|
@ -2,7 +2,7 @@
|
||||||
*
|
*
|
||||||
* $Id$
|
* $Id$
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006-2009 Florian Pose, Ingenieurgemeinschaft IgH
|
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||||
*
|
*
|
||||||
* This file is part of the IgH EtherCAT master userspace library.
|
* This file is part of the IgH EtherCAT master userspace library.
|
||||||
*
|
*
|
||||||
|
|
@ -30,25 +30,25 @@
|
||||||
|
|
||||||
#include <unistd.h> /* close() */
|
#include <unistd.h> /* close() */
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
#include "ioctl.h"
|
||||||
#include "master.h"
|
#include "master.h"
|
||||||
#include "domain.h"
|
#include "domain.h"
|
||||||
#include "slave_config.h"
|
#include "slave_config.h"
|
||||||
#include "master/ioctl.h"
|
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
int ecrt_master_reserve(ec_master_t *master)
|
int ecrt_master_reserve(ec_master_t *master)
|
||||||
{
|
{
|
||||||
if (ioctl(master->fd, EC_IOCTL_REQUEST, NULL) == -1) {
|
int ret = ioctl(master->fd, EC_IOCTL_REQUEST, NULL);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to reserve master: %s\n",
|
fprintf(stderr, "Failed to reserve master: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
return -1;
|
return -EC_IOCTL_ERRNO(ret);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -88,7 +88,11 @@ void ec_master_clear(ec_master_t *master)
|
||||||
ec_master_clear_config(master);
|
ec_master_clear_config(master);
|
||||||
|
|
||||||
if (master->fd != -1) {
|
if (master->fd != -1) {
|
||||||
|
#if USE_RTDM
|
||||||
|
rt_dev_close(master->fd);
|
||||||
|
#else
|
||||||
close(master->fd);
|
close(master->fd);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -121,8 +125,9 @@ ec_domain_t *ecrt_master_create_domain(ec_master_t *master)
|
||||||
}
|
}
|
||||||
|
|
||||||
index = ioctl(master->fd, EC_IOCTL_CREATE_DOMAIN, NULL);
|
index = ioctl(master->fd, EC_IOCTL_CREATE_DOMAIN, NULL);
|
||||||
if (index == -1) {
|
if (EC_IOCTL_IS_ERROR(index)) {
|
||||||
fprintf(stderr, "Failed to create domain: %s\n", strerror(errno));
|
fprintf(stderr, "Failed to create domain: %s\n",
|
||||||
|
strerror(EC_IOCTL_ERRNO(index)));
|
||||||
free(domain);
|
free(domain);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -160,6 +165,7 @@ ec_slave_config_t *ecrt_master_slave_config(ec_master_t *master,
|
||||||
{
|
{
|
||||||
ec_ioctl_config_t data;
|
ec_ioctl_config_t data;
|
||||||
ec_slave_config_t *sc;
|
ec_slave_config_t *sc;
|
||||||
|
int ret;
|
||||||
|
|
||||||
sc = malloc(sizeof(ec_slave_config_t));
|
sc = malloc(sizeof(ec_slave_config_t));
|
||||||
if (!sc) {
|
if (!sc) {
|
||||||
|
|
@ -172,9 +178,10 @@ ec_slave_config_t *ecrt_master_slave_config(ec_master_t *master,
|
||||||
data.vendor_id = vendor_id;
|
data.vendor_id = vendor_id;
|
||||||
data.product_code = product_code;
|
data.product_code = product_code;
|
||||||
|
|
||||||
if (ioctl(master->fd, EC_IOCTL_CREATE_SLAVE_CONFIG, &data) == -1) {
|
ret = ioctl(master->fd, EC_IOCTL_CREATE_SLAVE_CONFIG, &data);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to create slave config: %s\n",
|
fprintf(stderr, "Failed to create slave config: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
free(sc);
|
free(sc);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -194,13 +201,16 @@ ec_slave_config_t *ecrt_master_slave_config(ec_master_t *master,
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
int ecrt_master(ec_master_t* master, ec_master_info_t *master_info)
|
int ecrt_master(ec_master_t *master, ec_master_info_t *master_info)
|
||||||
{
|
{
|
||||||
ec_ioctl_master_t data;
|
ec_ioctl_master_t data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (ioctl(master->fd, EC_IOCTL_MASTER, &data) < 0) {
|
ret = ioctl(master->fd, EC_IOCTL_MASTER, &data);
|
||||||
fprintf(stderr, "Failed to get master info: %s\n", strerror(errno));
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
return -1;
|
fprintf(stderr, "Failed to get master info: %s\n",
|
||||||
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
|
return -EC_IOCTL_ERRNO(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
master_info->slave_count = data.slave_count;
|
master_info->slave_count = data.slave_count;
|
||||||
|
|
@ -216,13 +226,15 @@ int ecrt_master_get_slave(ec_master_t *master, uint16_t slave_position,
|
||||||
ec_slave_info_t *slave_info)
|
ec_slave_info_t *slave_info)
|
||||||
{
|
{
|
||||||
ec_ioctl_slave_t data;
|
ec_ioctl_slave_t data;
|
||||||
int i;
|
int ret, i;
|
||||||
|
|
||||||
data.position = slave_position;
|
data.position = slave_position;
|
||||||
|
|
||||||
if (ioctl(master->fd, EC_IOCTL_SLAVE, &data) == -1) {
|
ret = ioctl(master->fd, EC_IOCTL_SLAVE, &data);
|
||||||
fprintf(stderr, "Failed to get slave info: %s\n", strerror(errno));
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
return -1;
|
fprintf(stderr, "Failed to get slave info: %s\n",
|
||||||
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
|
return -EC_IOCTL_ERRNO(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
slave_info->position = data.position;
|
slave_info->position = data.position;
|
||||||
|
|
@ -232,7 +244,7 @@ int ecrt_master_get_slave(ec_master_t *master, uint16_t slave_position,
|
||||||
slave_info->serial_number = data.serial_number;
|
slave_info->serial_number = data.serial_number;
|
||||||
slave_info->alias = data.alias;
|
slave_info->alias = data.alias;
|
||||||
slave_info->current_on_ebus = data.current_on_ebus;
|
slave_info->current_on_ebus = data.current_on_ebus;
|
||||||
for ( i = 0; i < EC_MAX_PORTS; i++ ) {
|
for (i = 0; i < EC_MAX_PORTS; i++) {
|
||||||
slave_info->ports[i].desc = data.ports[i].desc;
|
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.link_up = data.ports[i].link.link_up;
|
||||||
slave_info->ports[i].link.loop_closed =
|
slave_info->ports[i].link.loop_closed =
|
||||||
|
|
@ -258,6 +270,7 @@ int ecrt_master_get_sync_manager(ec_master_t *master, uint16_t slave_position,
|
||||||
uint8_t sync_index, ec_sync_info_t *sync)
|
uint8_t sync_index, ec_sync_info_t *sync)
|
||||||
{
|
{
|
||||||
ec_ioctl_slave_sync_t data;
|
ec_ioctl_slave_sync_t data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (sync_index >= EC_MAX_SYNC_MANAGERS) {
|
if (sync_index >= EC_MAX_SYNC_MANAGERS) {
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
@ -267,10 +280,11 @@ int ecrt_master_get_sync_manager(ec_master_t *master, uint16_t slave_position,
|
||||||
data.slave_position = slave_position;
|
data.slave_position = slave_position;
|
||||||
data.sync_index = sync_index;
|
data.sync_index = sync_index;
|
||||||
|
|
||||||
if (ioctl(master->fd, EC_IOCTL_SLAVE_SYNC, &data) == -1) {
|
ret = ioctl(master->fd, EC_IOCTL_SLAVE_SYNC, &data);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to get sync manager information: %s\n",
|
fprintf(stderr, "Failed to get sync manager information: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
return -1; // FIXME
|
return -EC_IOCTL_ERRNO(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
sync->index = sync_index;
|
sync->index = sync_index;
|
||||||
|
|
@ -290,6 +304,7 @@ int ecrt_master_get_pdo(ec_master_t *master, uint16_t slave_position,
|
||||||
uint8_t sync_index, uint16_t pos, ec_pdo_info_t *pdo)
|
uint8_t sync_index, uint16_t pos, ec_pdo_info_t *pdo)
|
||||||
{
|
{
|
||||||
ec_ioctl_slave_sync_pdo_t data;
|
ec_ioctl_slave_sync_pdo_t data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (sync_index >= EC_MAX_SYNC_MANAGERS)
|
if (sync_index >= EC_MAX_SYNC_MANAGERS)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
@ -299,10 +314,11 @@ int ecrt_master_get_pdo(ec_master_t *master, uint16_t slave_position,
|
||||||
data.sync_index = sync_index;
|
data.sync_index = sync_index;
|
||||||
data.pdo_pos = pos;
|
data.pdo_pos = pos;
|
||||||
|
|
||||||
if (ioctl(master->fd, EC_IOCTL_SLAVE_SYNC_PDO, &data) == -1) {
|
ret = ioctl(master->fd, EC_IOCTL_SLAVE_SYNC_PDO, &data);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to get pdo information: %s\n",
|
fprintf(stderr, "Failed to get pdo information: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
return -1; // FIXME
|
return -EC_IOCTL_ERRNO(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
pdo->index = data.index;
|
pdo->index = data.index;
|
||||||
|
|
@ -319,6 +335,7 @@ int ecrt_master_get_pdo_entry(ec_master_t *master, uint16_t slave_position,
|
||||||
ec_pdo_entry_info_t *entry)
|
ec_pdo_entry_info_t *entry)
|
||||||
{
|
{
|
||||||
ec_ioctl_slave_sync_pdo_entry_t data;
|
ec_ioctl_slave_sync_pdo_entry_t data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (sync_index >= EC_MAX_SYNC_MANAGERS)
|
if (sync_index >= EC_MAX_SYNC_MANAGERS)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
@ -329,10 +346,11 @@ int ecrt_master_get_pdo_entry(ec_master_t *master, uint16_t slave_position,
|
||||||
data.pdo_pos = pdo_pos;
|
data.pdo_pos = pdo_pos;
|
||||||
data.entry_pos = entry_pos;
|
data.entry_pos = entry_pos;
|
||||||
|
|
||||||
if (ioctl(master->fd, EC_IOCTL_SLAVE_SYNC_PDO_ENTRY, &data) == -1) {
|
ret = ioctl(master->fd, EC_IOCTL_SLAVE_SYNC_PDO_ENTRY, &data);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to get pdo entry information: %s\n",
|
fprintf(stderr, "Failed to get pdo entry information: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
return -1; // FIXME
|
return -EC_IOCTL_ERRNO(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
entry->index = data.index;
|
entry->index = data.index;
|
||||||
|
|
@ -349,6 +367,7 @@ int ecrt_master_sdo_download(ec_master_t *master, uint16_t slave_position,
|
||||||
size_t data_size, uint32_t *abort_code)
|
size_t data_size, uint32_t *abort_code)
|
||||||
{
|
{
|
||||||
ec_ioctl_slave_sdo_download_t download;
|
ec_ioctl_slave_sdo_download_t download;
|
||||||
|
int ret;
|
||||||
|
|
||||||
download.slave_position = slave_position;
|
download.slave_position = slave_position;
|
||||||
download.sdo_index = index;
|
download.sdo_index = index;
|
||||||
|
|
@ -357,13 +376,14 @@ int ecrt_master_sdo_download(ec_master_t *master, uint16_t slave_position,
|
||||||
download.data_size = data_size;
|
download.data_size = data_size;
|
||||||
download.data = data;
|
download.data = data;
|
||||||
|
|
||||||
if (ioctl(master->fd, EC_IOCTL_SLAVE_SDO_DOWNLOAD, &download) == -1) {
|
ret = ioctl(master->fd, EC_IOCTL_SLAVE_SDO_DOWNLOAD, &download);
|
||||||
if (errno == EIO && abort_code) {
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
|
if (EC_IOCTL_ERRNO(ret) == EIO && abort_code) {
|
||||||
*abort_code = download.abort_code;
|
*abort_code = download.abort_code;
|
||||||
}
|
}
|
||||||
fprintf(stderr, "Failed to execute SDO download: %s\n",
|
fprintf(stderr, "Failed to execute SDO download: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
return -1;
|
return -EC_IOCTL_ERRNO(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -376,6 +396,7 @@ int ecrt_master_sdo_download_complete(ec_master_t *master,
|
||||||
size_t data_size, uint32_t *abort_code)
|
size_t data_size, uint32_t *abort_code)
|
||||||
{
|
{
|
||||||
ec_ioctl_slave_sdo_download_t download;
|
ec_ioctl_slave_sdo_download_t download;
|
||||||
|
int ret;
|
||||||
|
|
||||||
download.slave_position = slave_position;
|
download.slave_position = slave_position;
|
||||||
download.sdo_index = index;
|
download.sdo_index = index;
|
||||||
|
|
@ -384,13 +405,14 @@ int ecrt_master_sdo_download_complete(ec_master_t *master,
|
||||||
download.data_size = data_size;
|
download.data_size = data_size;
|
||||||
download.data = data;
|
download.data = data;
|
||||||
|
|
||||||
if (ioctl(master->fd, EC_IOCTL_SLAVE_SDO_DOWNLOAD, &download) == -1) {
|
ret = ioctl(master->fd, EC_IOCTL_SLAVE_SDO_DOWNLOAD, &download);
|
||||||
if (errno == EIO && abort_code) {
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
|
if (EC_IOCTL_ERRNO(ret) == EIO && abort_code) {
|
||||||
*abort_code = download.abort_code;
|
*abort_code = download.abort_code;
|
||||||
}
|
}
|
||||||
fprintf(stderr, "Failed to execute SDO download: %s\n",
|
fprintf(stderr, "Failed to execute SDO download: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
return -1;
|
return -EC_IOCTL_ERRNO(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -403,6 +425,7 @@ int ecrt_master_sdo_upload(ec_master_t *master, uint16_t slave_position,
|
||||||
size_t target_size, size_t *result_size, uint32_t *abort_code)
|
size_t target_size, size_t *result_size, uint32_t *abort_code)
|
||||||
{
|
{
|
||||||
ec_ioctl_slave_sdo_upload_t upload;
|
ec_ioctl_slave_sdo_upload_t upload;
|
||||||
|
int ret;
|
||||||
|
|
||||||
upload.slave_position = slave_position;
|
upload.slave_position = slave_position;
|
||||||
upload.sdo_index = index;
|
upload.sdo_index = index;
|
||||||
|
|
@ -410,13 +433,14 @@ int ecrt_master_sdo_upload(ec_master_t *master, uint16_t slave_position,
|
||||||
upload.target_size = target_size;
|
upload.target_size = target_size;
|
||||||
upload.target = target;
|
upload.target = target;
|
||||||
|
|
||||||
if (ioctl(master->fd, EC_IOCTL_SLAVE_SDO_UPLOAD, &upload) == -1) {
|
ret = ioctl(master->fd, EC_IOCTL_SLAVE_SDO_UPLOAD, &upload);
|
||||||
if (errno == EIO && abort_code) {
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
|
if (EC_IOCTL_ERRNO(ret) == EIO && abort_code) {
|
||||||
*abort_code = upload.abort_code;
|
*abort_code = upload.abort_code;
|
||||||
}
|
}
|
||||||
fprintf(stderr, "Failed to execute SDO upload: %s\n",
|
fprintf(stderr, "Failed to execute SDO upload: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
return -1;
|
return -EC_IOCTL_ERRNO(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
*result_size = upload.data_size;
|
*result_size = upload.data_size;
|
||||||
|
|
@ -430,6 +454,7 @@ int ecrt_master_write_idn(ec_master_t *master, uint16_t slave_position,
|
||||||
uint16_t *error_code)
|
uint16_t *error_code)
|
||||||
{
|
{
|
||||||
ec_ioctl_slave_soe_write_t io;
|
ec_ioctl_slave_soe_write_t io;
|
||||||
|
int ret;
|
||||||
|
|
||||||
io.slave_position = slave_position;
|
io.slave_position = slave_position;
|
||||||
io.drive_no = drive_no;
|
io.drive_no = drive_no;
|
||||||
|
|
@ -437,12 +462,14 @@ int ecrt_master_write_idn(ec_master_t *master, uint16_t slave_position,
|
||||||
io.data_size = data_size;
|
io.data_size = data_size;
|
||||||
io.data = data;
|
io.data = data;
|
||||||
|
|
||||||
if (ioctl(master->fd, EC_IOCTL_SLAVE_SOE_WRITE, &io) == -1) {
|
ret = ioctl(master->fd, EC_IOCTL_SLAVE_SOE_WRITE, &io);
|
||||||
if (errno == EIO && error_code) {
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
|
if (EC_IOCTL_ERRNO(ret) == EIO && error_code) {
|
||||||
*error_code = io.error_code;
|
*error_code = io.error_code;
|
||||||
}
|
}
|
||||||
fprintf(stderr, "Failed to write IDN: %s\n", strerror(errno));
|
fprintf(stderr, "Failed to write IDN: %s\n",
|
||||||
return -1;
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
|
return -EC_IOCTL_ERRNO(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -455,6 +482,7 @@ int ecrt_master_read_idn(ec_master_t *master, uint16_t slave_position,
|
||||||
size_t *result_size, uint16_t *error_code)
|
size_t *result_size, uint16_t *error_code)
|
||||||
{
|
{
|
||||||
ec_ioctl_slave_soe_read_t io;
|
ec_ioctl_slave_soe_read_t io;
|
||||||
|
int ret;
|
||||||
|
|
||||||
io.slave_position = slave_position;
|
io.slave_position = slave_position;
|
||||||
io.drive_no = drive_no;
|
io.drive_no = drive_no;
|
||||||
|
|
@ -462,12 +490,14 @@ int ecrt_master_read_idn(ec_master_t *master, uint16_t slave_position,
|
||||||
io.mem_size = target_size;
|
io.mem_size = target_size;
|
||||||
io.data = target;
|
io.data = target;
|
||||||
|
|
||||||
if (ioctl(master->fd, EC_IOCTL_SLAVE_SOE_READ, &io) == -1) {
|
ret = ioctl(master->fd, EC_IOCTL_SLAVE_SOE_READ, &io);
|
||||||
if (errno == EIO && error_code) {
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
|
if (EC_IOCTL_ERRNO(ret) == EIO && error_code) {
|
||||||
*error_code = io.error_code;
|
*error_code = io.error_code;
|
||||||
}
|
}
|
||||||
fprintf(stderr, "Failed to read IDN: %s\n", strerror(errno));
|
fprintf(stderr, "Failed to read IDN: %s\n",
|
||||||
return -1;
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
|
return -EC_IOCTL_ERRNO(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
*result_size = io.data_size;
|
*result_size = io.data_size;
|
||||||
|
|
@ -478,23 +508,35 @@ int ecrt_master_read_idn(ec_master_t *master, uint16_t slave_position,
|
||||||
|
|
||||||
int ecrt_master_activate(ec_master_t *master)
|
int ecrt_master_activate(ec_master_t *master)
|
||||||
{
|
{
|
||||||
if (ioctl(master->fd, EC_IOCTL_ACTIVATE,
|
ec_ioctl_master_activate_t io;
|
||||||
&master->process_data_size) == -1) {
|
int ret;
|
||||||
|
|
||||||
|
ret = ioctl(master->fd, EC_IOCTL_ACTIVATE, &io);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to activate master: %s\n",
|
fprintf(stderr, "Failed to activate master: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
return -1; // FIXME
|
return -EC_IOCTL_ERRNO(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
master->process_data_size = io.process_data_size;
|
||||||
|
|
||||||
if (master->process_data_size) {
|
if (master->process_data_size) {
|
||||||
|
#ifdef USE_RTDM
|
||||||
|
/* memory-mapping was already done in kernel. The user-space addess is
|
||||||
|
* provided in the ioctl data.
|
||||||
|
*/
|
||||||
|
master->process_data = io.process_data;
|
||||||
|
#else
|
||||||
master->process_data = mmap(0, master->process_data_size,
|
master->process_data = mmap(0, master->process_data_size,
|
||||||
PROT_READ | PROT_WRITE, MAP_SHARED, master->fd, 0);
|
PROT_READ | PROT_WRITE, MAP_SHARED, master->fd, 0);
|
||||||
if (master->process_data == MAP_FAILED) {
|
if (master->process_data == MAP_FAILED) {
|
||||||
fprintf(stderr, "Failed to map process data: %s",
|
fprintf(stderr, "Failed to map process data: %s\n",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
master->process_data = NULL;
|
master->process_data = NULL;
|
||||||
master->process_data_size = 0;
|
master->process_data_size = 0;
|
||||||
return -1; // FIXME
|
return -errno;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Access the mapped region to cause the initial page fault
|
// Access the mapped region to cause the initial page fault
|
||||||
master->process_data[0] = 0x00;
|
master->process_data[0] = 0x00;
|
||||||
|
|
@ -507,8 +549,12 @@ int ecrt_master_activate(ec_master_t *master)
|
||||||
|
|
||||||
void ecrt_master_deactivate(ec_master_t *master)
|
void ecrt_master_deactivate(ec_master_t *master)
|
||||||
{
|
{
|
||||||
if (ioctl(master->fd, EC_IOCTL_DEACTIVATE, NULL) == -1) {
|
int ret;
|
||||||
fprintf(stderr, "Failed to deactivate master: %s\n", strerror(errno));
|
|
||||||
|
ret = ioctl(master->fd, EC_IOCTL_DEACTIVATE, NULL);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
|
fprintf(stderr, "Failed to deactivate master: %s\n",
|
||||||
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -520,12 +566,15 @@ void ecrt_master_deactivate(ec_master_t *master)
|
||||||
int ecrt_master_set_send_interval(ec_master_t *master,
|
int ecrt_master_set_send_interval(ec_master_t *master,
|
||||||
size_t send_interval_us)
|
size_t send_interval_us)
|
||||||
{
|
{
|
||||||
if (ioctl(master->fd, EC_IOCTL_SET_SEND_INTERVAL,
|
int ret;
|
||||||
&send_interval_us) == -1) {
|
|
||||||
|
ret = ioctl(master->fd, EC_IOCTL_SET_SEND_INTERVAL, &send_interval_us);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to set send interval: %s\n",
|
fprintf(stderr, "Failed to set send interval: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
return -1; // FIXME
|
return -EC_IOCTL_ERRNO(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -533,8 +582,12 @@ int ecrt_master_set_send_interval(ec_master_t *master,
|
||||||
|
|
||||||
void ecrt_master_send(ec_master_t *master)
|
void ecrt_master_send(ec_master_t *master)
|
||||||
{
|
{
|
||||||
if (ioctl(master->fd, EC_IOCTL_SEND, NULL) == -1) {
|
int ret;
|
||||||
fprintf(stderr, "Failed to send: %s\n", strerror(errno));
|
|
||||||
|
ret = ioctl(master->fd, EC_IOCTL_SEND, NULL);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
|
fprintf(stderr, "Failed to send: %s\n",
|
||||||
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -542,8 +595,12 @@ void ecrt_master_send(ec_master_t *master)
|
||||||
|
|
||||||
void ecrt_master_receive(ec_master_t *master)
|
void ecrt_master_receive(ec_master_t *master)
|
||||||
{
|
{
|
||||||
if (ioctl(master->fd, EC_IOCTL_RECEIVE, NULL) == -1) {
|
int ret;
|
||||||
fprintf(stderr, "Failed to receive: %s\n", strerror(errno));
|
|
||||||
|
ret = ioctl(master->fd, EC_IOCTL_RECEIVE, NULL);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
|
fprintf(stderr, "Failed to receive: %s\n",
|
||||||
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -551,8 +608,12 @@ void ecrt_master_receive(ec_master_t *master)
|
||||||
|
|
||||||
void ecrt_master_state(const ec_master_t *master, ec_master_state_t *state)
|
void ecrt_master_state(const ec_master_t *master, ec_master_state_t *state)
|
||||||
{
|
{
|
||||||
if (ioctl(master->fd, EC_IOCTL_MASTER_STATE, state) == -1) {
|
int ret;
|
||||||
fprintf(stderr, "Failed to get master state: %s\n", strerror(errno));
|
|
||||||
|
ret = ioctl(master->fd, EC_IOCTL_MASTER_STATE, state);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
|
fprintf(stderr, "Failed to get master state: %s\n",
|
||||||
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -562,12 +623,16 @@ int ecrt_master_link_state(const ec_master_t *master, unsigned int dev_idx,
|
||||||
ec_master_link_state_t *state)
|
ec_master_link_state_t *state)
|
||||||
{
|
{
|
||||||
ec_ioctl_link_state_t io;
|
ec_ioctl_link_state_t io;
|
||||||
|
int ret;
|
||||||
|
|
||||||
io.dev_idx = dev_idx;
|
io.dev_idx = dev_idx;
|
||||||
io.state = state;
|
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));
|
ret = ioctl(master->fd, EC_IOCTL_MASTER_LINK_STATE, &io);
|
||||||
return -errno;
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
|
fprintf(stderr, "Failed to get link state: %s\n",
|
||||||
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
|
return -EC_IOCTL_ERRNO(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -578,12 +643,14 @@ 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)
|
void ecrt_master_application_time(ec_master_t *master, uint64_t app_time)
|
||||||
{
|
{
|
||||||
ec_ioctl_app_time_t data;
|
ec_ioctl_app_time_t data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
data.app_time = app_time;
|
data.app_time = app_time;
|
||||||
|
|
||||||
if (ioctl(master->fd, EC_IOCTL_APP_TIME, &data) == -1) {
|
ret = ioctl(master->fd, EC_IOCTL_APP_TIME, &data);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to set application time: %s\n",
|
fprintf(stderr, "Failed to set application time: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -591,9 +658,12 @@ void ecrt_master_application_time(ec_master_t *master, uint64_t app_time)
|
||||||
|
|
||||||
void ecrt_master_sync_reference_clock(ec_master_t *master)
|
void ecrt_master_sync_reference_clock(ec_master_t *master)
|
||||||
{
|
{
|
||||||
if (ioctl(master->fd, EC_IOCTL_SYNC_REF, NULL) == -1) {
|
int ret;
|
||||||
|
|
||||||
|
ret = ioctl(master->fd, EC_IOCTL_SYNC_REF, NULL);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to sync reference clock: %s\n",
|
fprintf(stderr, "Failed to sync reference clock: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -601,8 +671,12 @@ void ecrt_master_sync_reference_clock(ec_master_t *master)
|
||||||
|
|
||||||
void ecrt_master_sync_slave_clocks(ec_master_t *master)
|
void ecrt_master_sync_slave_clocks(ec_master_t *master)
|
||||||
{
|
{
|
||||||
if (ioctl(master->fd, EC_IOCTL_SYNC_SLAVES, NULL) == -1) {
|
int ret;
|
||||||
fprintf(stderr, "Failed to sync slave clocks: %s\n", strerror(errno));
|
|
||||||
|
ret = ioctl(master->fd, EC_IOCTL_SYNC_SLAVES, NULL);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
|
fprintf(stderr, "Failed to sync slave clocks: %s\n",
|
||||||
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -610,9 +684,12 @@ void ecrt_master_sync_slave_clocks(ec_master_t *master)
|
||||||
|
|
||||||
void ecrt_master_sync_monitor_queue(ec_master_t *master)
|
void ecrt_master_sync_monitor_queue(ec_master_t *master)
|
||||||
{
|
{
|
||||||
if (ioctl(master->fd, EC_IOCTL_SYNC_MON_QUEUE, NULL) == -1) {
|
int ret;
|
||||||
|
|
||||||
|
ret = ioctl(master->fd, EC_IOCTL_SYNC_MON_QUEUE, NULL);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to queue sync monitor datagram: %s\n",
|
fprintf(stderr, "Failed to queue sync monitor datagram: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -621,11 +698,13 @@ void ecrt_master_sync_monitor_queue(ec_master_t *master)
|
||||||
uint32_t ecrt_master_sync_monitor_process(ec_master_t *master)
|
uint32_t ecrt_master_sync_monitor_process(ec_master_t *master)
|
||||||
{
|
{
|
||||||
uint32_t time_diff;
|
uint32_t time_diff;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (ioctl(master->fd, EC_IOCTL_SYNC_MON_PROCESS, &time_diff) == -1) {
|
ret = ioctl(master->fd, EC_IOCTL_SYNC_MON_PROCESS, &time_diff);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
time_diff = 0xffffffff;
|
time_diff = 0xffffffff;
|
||||||
fprintf(stderr, "Failed to process sync monitor datagram: %s\n",
|
fprintf(stderr, "Failed to process sync monitor datagram: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return time_diff;
|
return time_diff;
|
||||||
|
|
@ -635,8 +714,12 @@ uint32_t ecrt_master_sync_monitor_process(ec_master_t *master)
|
||||||
|
|
||||||
void ecrt_master_reset(ec_master_t *master)
|
void ecrt_master_reset(ec_master_t *master)
|
||||||
{
|
{
|
||||||
if (ioctl(master->fd, EC_IOCTL_RESET, NULL) == -1) {
|
int ret;
|
||||||
fprintf(stderr, "Failed to reset master: %s\n", strerror(errno));
|
|
||||||
|
ret = ioctl(master->fd, EC_IOCTL_RESET, NULL);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
|
fprintf(stderr, "Failed to reset master: %s\n",
|
||||||
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
*
|
*
|
||||||
* $Id$
|
* $Id$
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006-2009 Florian Pose, Ingenieurgemeinschaft IgH
|
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||||
*
|
*
|
||||||
* This file is part of the IgH EtherCAT master userspace library.
|
* This file is part of the IgH EtherCAT master userspace library.
|
||||||
*
|
*
|
||||||
|
|
@ -35,12 +35,10 @@
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/ioctl.h>
|
|
||||||
|
|
||||||
|
#include "ioctl.h"
|
||||||
#include "sdo_request.h"
|
#include "sdo_request.h"
|
||||||
#include "master/ioctl.h"
|
|
||||||
#include "slave_config.h"
|
#include "slave_config.h"
|
||||||
#include "master.h"
|
#include "master.h"
|
||||||
|
|
||||||
|
|
@ -60,15 +58,17 @@ void ec_sdo_request_clear(ec_sdo_request_t *req)
|
||||||
void ecrt_sdo_request_timeout(ec_sdo_request_t *req, uint32_t timeout)
|
void ecrt_sdo_request_timeout(ec_sdo_request_t *req, uint32_t timeout)
|
||||||
{
|
{
|
||||||
ec_ioctl_sdo_request_t data;
|
ec_ioctl_sdo_request_t data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
data.config_index = req->config->index;
|
data.config_index = req->config->index;
|
||||||
data.request_index = req->index;
|
data.request_index = req->index;
|
||||||
data.timeout = timeout;
|
data.timeout = timeout;
|
||||||
|
|
||||||
if (ioctl(req->config->master->fd, EC_IOCTL_SDO_REQUEST_TIMEOUT,
|
ret = ioctl(req->config->master->fd, EC_IOCTL_SDO_REQUEST_TIMEOUT, &data);
|
||||||
&data) == -1)
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to set SDO request timeout: %s\n",
|
fprintf(stderr, "Failed to set SDO request timeout: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
@ -90,14 +90,17 @@ size_t ecrt_sdo_request_data_size(const ec_sdo_request_t *req)
|
||||||
ec_request_state_t ecrt_sdo_request_state(ec_sdo_request_t *req)
|
ec_request_state_t ecrt_sdo_request_state(ec_sdo_request_t *req)
|
||||||
{
|
{
|
||||||
ec_ioctl_sdo_request_t data;
|
ec_ioctl_sdo_request_t data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
data.config_index = req->config->index;
|
data.config_index = req->config->index;
|
||||||
data.request_index = req->index;
|
data.request_index = req->index;
|
||||||
|
|
||||||
if (ioctl(req->config->master->fd, EC_IOCTL_SDO_REQUEST_STATE,
|
ret = ioctl(req->config->master->fd, EC_IOCTL_SDO_REQUEST_STATE, &data);
|
||||||
&data) == -1)
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to get SDO request state: %s\n",
|
fprintf(stderr, "Failed to get SDO request state: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
|
return EC_REQUEST_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
if (data.size) { // new data waiting to be copied
|
if (data.size) { // new data waiting to be copied
|
||||||
if (req->mem_size < data.size) {
|
if (req->mem_size < data.size) {
|
||||||
|
|
@ -108,9 +111,11 @@ ec_request_state_t ecrt_sdo_request_state(ec_sdo_request_t *req)
|
||||||
|
|
||||||
data.data = req->data;
|
data.data = req->data;
|
||||||
|
|
||||||
if (ioctl(req->config->master->fd, EC_IOCTL_SDO_REQUEST_DATA,
|
ret = ioctl(req->config->master->fd,
|
||||||
&data) == -1) {
|
EC_IOCTL_SDO_REQUEST_DATA, &data);
|
||||||
fprintf(stderr, "Failed to get SDO data: %s\n", strerror(errno));
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
|
fprintf(stderr, "Failed to get SDO data: %s\n",
|
||||||
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
return EC_REQUEST_ERROR;
|
return EC_REQUEST_ERROR;
|
||||||
}
|
}
|
||||||
req->data_size = data.size;
|
req->data_size = data.size;
|
||||||
|
|
@ -124,14 +129,16 @@ ec_request_state_t ecrt_sdo_request_state(ec_sdo_request_t *req)
|
||||||
void ecrt_sdo_request_read(ec_sdo_request_t *req)
|
void ecrt_sdo_request_read(ec_sdo_request_t *req)
|
||||||
{
|
{
|
||||||
ec_ioctl_sdo_request_t data;
|
ec_ioctl_sdo_request_t data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
data.config_index = req->config->index;
|
data.config_index = req->config->index;
|
||||||
data.request_index = req->index;
|
data.request_index = req->index;
|
||||||
|
|
||||||
if (ioctl(req->config->master->fd, EC_IOCTL_SDO_REQUEST_READ,
|
ret = ioctl(req->config->master->fd, EC_IOCTL_SDO_REQUEST_READ, &data);
|
||||||
&data) == -1)
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to command an SDO read operation : %s\n",
|
fprintf(stderr, "Failed to command an SDO read operation : %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
@ -139,16 +146,18 @@ void ecrt_sdo_request_read(ec_sdo_request_t *req)
|
||||||
void ecrt_sdo_request_write(ec_sdo_request_t *req)
|
void ecrt_sdo_request_write(ec_sdo_request_t *req)
|
||||||
{
|
{
|
||||||
ec_ioctl_sdo_request_t data;
|
ec_ioctl_sdo_request_t data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
data.config_index = req->config->index;
|
data.config_index = req->config->index;
|
||||||
data.request_index = req->index;
|
data.request_index = req->index;
|
||||||
data.data = req->data;
|
data.data = req->data;
|
||||||
data.size = req->data_size;
|
data.size = req->data_size;
|
||||||
|
|
||||||
if (ioctl(req->config->master->fd, EC_IOCTL_SDO_REQUEST_WRITE,
|
ret = ioctl(req->config->master->fd, EC_IOCTL_SDO_REQUEST_WRITE, &data);
|
||||||
&data) == -1)
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to command an SDO write operation : %s\n",
|
fprintf(stderr, "Failed to command an SDO write operation : %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
*
|
*
|
||||||
* $Id$
|
* $Id$
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006-2009 Florian Pose, Ingenieurgemeinschaft IgH
|
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||||
*
|
*
|
||||||
* This file is part of the IgH EtherCAT master userspace library.
|
* This file is part of the IgH EtherCAT master userspace library.
|
||||||
*
|
*
|
||||||
|
|
@ -29,17 +29,16 @@
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <errno.h> /* ENOENT */
|
||||||
|
|
||||||
|
#include "ioctl.h"
|
||||||
#include "slave_config.h"
|
#include "slave_config.h"
|
||||||
#include "domain.h"
|
#include "domain.h"
|
||||||
#include "sdo_request.h"
|
#include "sdo_request.h"
|
||||||
#include "voe_handler.h"
|
#include "voe_handler.h"
|
||||||
#include "master.h"
|
#include "master.h"
|
||||||
#include "master/ioctl.h"
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
@ -70,6 +69,7 @@ int ecrt_slave_config_sync_manager(ec_slave_config_t *sc, uint8_t sync_index,
|
||||||
ec_direction_t dir, ec_watchdog_mode_t watchdog_mode)
|
ec_direction_t dir, ec_watchdog_mode_t watchdog_mode)
|
||||||
{
|
{
|
||||||
ec_ioctl_config_t data;
|
ec_ioctl_config_t data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (sync_index >= EC_MAX_SYNC_MANAGERS)
|
if (sync_index >= EC_MAX_SYNC_MANAGERS)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
@ -80,10 +80,11 @@ int ecrt_slave_config_sync_manager(ec_slave_config_t *sc, uint8_t sync_index,
|
||||||
data.syncs[sync_index].watchdog_mode = watchdog_mode;
|
data.syncs[sync_index].watchdog_mode = watchdog_mode;
|
||||||
data.syncs[sync_index].config_this = 1;
|
data.syncs[sync_index].config_this = 1;
|
||||||
|
|
||||||
if (ioctl(sc->master->fd, EC_IOCTL_SC_SYNC, &data) == -1) {
|
ret = ioctl(sc->master->fd, EC_IOCTL_SC_SYNC, &data);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to config sync manager: %s\n",
|
fprintf(stderr, "Failed to config sync manager: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
return -1; // FIXME
|
return -EC_IOCTL_ERRNO(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -95,15 +96,17 @@ void ecrt_slave_config_watchdog(ec_slave_config_t *sc,
|
||||||
uint16_t divider, uint16_t intervals)
|
uint16_t divider, uint16_t intervals)
|
||||||
{
|
{
|
||||||
ec_ioctl_config_t data;
|
ec_ioctl_config_t data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
memset(&data, 0x00, sizeof(ec_ioctl_config_t));
|
memset(&data, 0x00, sizeof(ec_ioctl_config_t));
|
||||||
data.config_index = sc->index;
|
data.config_index = sc->index;
|
||||||
data.watchdog_divider = divider;
|
data.watchdog_divider = divider;
|
||||||
data.watchdog_intervals = intervals;
|
data.watchdog_intervals = intervals;
|
||||||
|
|
||||||
if (ioctl(sc->master->fd, EC_IOCTL_SC_WATCHDOG, &data) == -1) {
|
ret = ioctl(sc->master->fd, EC_IOCTL_SC_WATCHDOG, &data);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to config watchdog: %s\n",
|
fprintf(stderr, "Failed to config watchdog: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -113,15 +116,17 @@ int ecrt_slave_config_pdo_assign_add(ec_slave_config_t *sc,
|
||||||
uint8_t sync_index, uint16_t pdo_index)
|
uint8_t sync_index, uint16_t pdo_index)
|
||||||
{
|
{
|
||||||
ec_ioctl_config_pdo_t data;
|
ec_ioctl_config_pdo_t data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
data.config_index = sc->index;
|
data.config_index = sc->index;
|
||||||
data.sync_index = sync_index;
|
data.sync_index = sync_index;
|
||||||
data.index = pdo_index;
|
data.index = pdo_index;
|
||||||
|
|
||||||
if (ioctl(sc->master->fd, EC_IOCTL_SC_ADD_PDO, &data) == -1) {
|
ret = ioctl(sc->master->fd, EC_IOCTL_SC_ADD_PDO, &data);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to add PDO: %s\n",
|
fprintf(stderr, "Failed to add PDO: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
return -1; // FIXME
|
return -EC_IOCTL_ERRNO(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -133,13 +138,15 @@ void ecrt_slave_config_pdo_assign_clear(ec_slave_config_t *sc,
|
||||||
uint8_t sync_index)
|
uint8_t sync_index)
|
||||||
{
|
{
|
||||||
ec_ioctl_config_pdo_t data;
|
ec_ioctl_config_pdo_t data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
data.config_index = sc->index;
|
data.config_index = sc->index;
|
||||||
data.sync_index = sync_index;
|
data.sync_index = sync_index;
|
||||||
|
|
||||||
if (ioctl(sc->master->fd, EC_IOCTL_SC_CLEAR_PDOS, &data) == -1) {
|
ret = ioctl(sc->master->fd, EC_IOCTL_SC_CLEAR_PDOS, &data);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to clear PDOs: %s\n",
|
fprintf(stderr, "Failed to clear PDOs: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -150,6 +157,7 @@ int ecrt_slave_config_pdo_mapping_add(ec_slave_config_t *sc,
|
||||||
uint8_t entry_bit_length)
|
uint8_t entry_bit_length)
|
||||||
{
|
{
|
||||||
ec_ioctl_add_pdo_entry_t data;
|
ec_ioctl_add_pdo_entry_t data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
data.config_index = sc->index;
|
data.config_index = sc->index;
|
||||||
data.pdo_index = pdo_index;
|
data.pdo_index = pdo_index;
|
||||||
|
|
@ -157,10 +165,11 @@ int ecrt_slave_config_pdo_mapping_add(ec_slave_config_t *sc,
|
||||||
data.entry_subindex = entry_subindex;
|
data.entry_subindex = entry_subindex;
|
||||||
data.entry_bit_length = entry_bit_length;
|
data.entry_bit_length = entry_bit_length;
|
||||||
|
|
||||||
if (ioctl(sc->master->fd, EC_IOCTL_SC_ADD_ENTRY, &data) == -1) {
|
ret = ioctl(sc->master->fd, EC_IOCTL_SC_ADD_ENTRY, &data);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to add PDO entry: %s\n",
|
fprintf(stderr, "Failed to add PDO entry: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
return -1; // FIXME
|
return -EC_IOCTL_ERRNO(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -172,13 +181,15 @@ void ecrt_slave_config_pdo_mapping_clear(ec_slave_config_t *sc,
|
||||||
uint16_t pdo_index)
|
uint16_t pdo_index)
|
||||||
{
|
{
|
||||||
ec_ioctl_config_pdo_t data;
|
ec_ioctl_config_pdo_t data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
data.config_index = sc->index;
|
data.config_index = sc->index;
|
||||||
data.index = pdo_index;
|
data.index = pdo_index;
|
||||||
|
|
||||||
if (ioctl(sc->master->fd, EC_IOCTL_SC_CLEAR_ENTRIES, &data) == -1) {
|
ret = ioctl(sc->master->fd, EC_IOCTL_SC_CLEAR_ENTRIES, &data);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to clear PDO entries: %s\n",
|
fprintf(stderr, "Failed to clear PDO entries: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -264,10 +275,10 @@ int ecrt_slave_config_reg_pdo_entry(
|
||||||
data.domain_index = domain->index;
|
data.domain_index = domain->index;
|
||||||
|
|
||||||
ret = ioctl(sc->master->fd, EC_IOCTL_SC_REG_PDO_ENTRY, &data);
|
ret = ioctl(sc->master->fd, EC_IOCTL_SC_REG_PDO_ENTRY, &data);
|
||||||
if (ret == -1) {
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to register PDO entry: %s\n",
|
fprintf(stderr, "Failed to register PDO entry: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
return -2; // FIXME
|
return -EC_IOCTL_ERRNO(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bit_position) {
|
if (bit_position) {
|
||||||
|
|
@ -277,7 +288,7 @@ int ecrt_slave_config_reg_pdo_entry(
|
||||||
fprintf(stderr, "PDO entry 0x%04X:%02X does not byte-align "
|
fprintf(stderr, "PDO entry 0x%04X:%02X does not byte-align "
|
||||||
"in config %u:%u.\n", index, subindex,
|
"in config %u:%u.\n", index, subindex,
|
||||||
sc->alias, sc->position);
|
sc->alias, sc->position);
|
||||||
return -3; // FIXME
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -291,6 +302,7 @@ void ecrt_slave_config_dc(ec_slave_config_t *sc, uint16_t assign_activate,
|
||||||
uint32_t sync1_cycle_time, uint32_t sync1_shift_time)
|
uint32_t sync1_cycle_time, uint32_t sync1_shift_time)
|
||||||
{
|
{
|
||||||
ec_ioctl_config_t data;
|
ec_ioctl_config_t data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
data.config_index = sc->index;
|
data.config_index = sc->index;
|
||||||
data.dc_assign_activate = assign_activate;
|
data.dc_assign_activate = assign_activate;
|
||||||
|
|
@ -299,8 +311,10 @@ void ecrt_slave_config_dc(ec_slave_config_t *sc, uint16_t assign_activate,
|
||||||
data.dc_sync[1].cycle_time = sync1_cycle_time;
|
data.dc_sync[1].cycle_time = sync1_cycle_time;
|
||||||
data.dc_sync[1].shift_time = sync1_shift_time;
|
data.dc_sync[1].shift_time = sync1_shift_time;
|
||||||
|
|
||||||
if (ioctl(sc->master->fd, EC_IOCTL_SC_DC, &data) == -1) {
|
ret = ioctl(sc->master->fd, EC_IOCTL_SC_DC, &data);
|
||||||
fprintf(stderr, "Failed to set assign_activate word.\n");
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
|
fprintf(stderr, "Failed to set assign_activate word: %s\n",
|
||||||
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -310,6 +324,7 @@ int ecrt_slave_config_sdo(ec_slave_config_t *sc, uint16_t index,
|
||||||
uint8_t subindex, const uint8_t *sdo_data, size_t size)
|
uint8_t subindex, const uint8_t *sdo_data, size_t size)
|
||||||
{
|
{
|
||||||
ec_ioctl_sc_sdo_t data;
|
ec_ioctl_sc_sdo_t data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
data.config_index = sc->index;
|
data.config_index = sc->index;
|
||||||
data.index = index;
|
data.index = index;
|
||||||
|
|
@ -318,9 +333,11 @@ int ecrt_slave_config_sdo(ec_slave_config_t *sc, uint16_t index,
|
||||||
data.size = size;
|
data.size = size;
|
||||||
data.complete_access = 0;
|
data.complete_access = 0;
|
||||||
|
|
||||||
if (ioctl(sc->master->fd, EC_IOCTL_SC_SDO, &data) == -1) {
|
ret = ioctl(sc->master->fd, EC_IOCTL_SC_SDO, &data);
|
||||||
fprintf(stderr, "Failed to configure SDO.\n");
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
return -1; // FIXME
|
fprintf(stderr, "Failed to configure SDO: %s\n",
|
||||||
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
|
return -EC_IOCTL_ERRNO(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -332,6 +349,7 @@ int ecrt_slave_config_complete_sdo(ec_slave_config_t *sc, uint16_t index,
|
||||||
const uint8_t *sdo_data, size_t size)
|
const uint8_t *sdo_data, size_t size)
|
||||||
{
|
{
|
||||||
ec_ioctl_sc_sdo_t data;
|
ec_ioctl_sc_sdo_t data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
data.config_index = sc->index;
|
data.config_index = sc->index;
|
||||||
data.index = index;
|
data.index = index;
|
||||||
|
|
@ -340,9 +358,11 @@ int ecrt_slave_config_complete_sdo(ec_slave_config_t *sc, uint16_t index,
|
||||||
data.size = size;
|
data.size = size;
|
||||||
data.complete_access = 1;
|
data.complete_access = 1;
|
||||||
|
|
||||||
if (ioctl(sc->master->fd, EC_IOCTL_SC_SDO, &data) == -1) {
|
ret = ioctl(sc->master->fd, EC_IOCTL_SC_SDO, &data);
|
||||||
fprintf(stderr, "Failed to configure SDO.\n");
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
return -1; // FIXME
|
fprintf(stderr, "Failed to configure SDO: %s\n",
|
||||||
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
|
return -EC_IOCTL_ERRNO(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -404,6 +424,7 @@ ec_sdo_request_t *ecrt_slave_config_create_sdo_request(ec_slave_config_t *sc,
|
||||||
{
|
{
|
||||||
ec_ioctl_sdo_request_t data;
|
ec_ioctl_sdo_request_t data;
|
||||||
ec_sdo_request_t *req;
|
ec_sdo_request_t *req;
|
||||||
|
int ret;
|
||||||
|
|
||||||
req = malloc(sizeof(ec_sdo_request_t));
|
req = malloc(sizeof(ec_sdo_request_t));
|
||||||
if (!req) {
|
if (!req) {
|
||||||
|
|
@ -428,9 +449,10 @@ ec_sdo_request_t *ecrt_slave_config_create_sdo_request(ec_slave_config_t *sc,
|
||||||
data.sdo_subindex = subindex;
|
data.sdo_subindex = subindex;
|
||||||
data.size = size;
|
data.size = size;
|
||||||
|
|
||||||
if (ioctl(sc->master->fd, EC_IOCTL_SC_SDO_REQUEST, &data) == -1) {
|
ret = ioctl(sc->master->fd, EC_IOCTL_SC_SDO_REQUEST, &data);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to create SDO request: %s\n",
|
fprintf(stderr, "Failed to create SDO request: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
ec_sdo_request_clear(req);
|
ec_sdo_request_clear(req);
|
||||||
free(req);
|
free(req);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -472,6 +494,7 @@ ec_voe_handler_t *ecrt_slave_config_create_voe_handler(ec_slave_config_t *sc,
|
||||||
{
|
{
|
||||||
ec_ioctl_voe_t data;
|
ec_ioctl_voe_t data;
|
||||||
ec_voe_handler_t *voe;
|
ec_voe_handler_t *voe;
|
||||||
|
int ret;
|
||||||
|
|
||||||
voe = malloc(sizeof(ec_voe_handler_t));
|
voe = malloc(sizeof(ec_voe_handler_t));
|
||||||
if (!voe) {
|
if (!voe) {
|
||||||
|
|
@ -494,9 +517,10 @@ ec_voe_handler_t *ecrt_slave_config_create_voe_handler(ec_slave_config_t *sc,
|
||||||
data.config_index = sc->index;
|
data.config_index = sc->index;
|
||||||
data.size = size;
|
data.size = size;
|
||||||
|
|
||||||
if (ioctl(sc->master->fd, EC_IOCTL_SC_VOE, &data) == -1) {
|
ret = ioctl(sc->master->fd, EC_IOCTL_SC_VOE, &data);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to create VoE handler: %s\n",
|
fprintf(stderr, "Failed to create VoE handler: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
ec_voe_handler_clear(voe);
|
ec_voe_handler_clear(voe);
|
||||||
free(voe);
|
free(voe);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -519,13 +543,15 @@ void ecrt_slave_config_state(const ec_slave_config_t *sc,
|
||||||
ec_slave_config_state_t *state)
|
ec_slave_config_state_t *state)
|
||||||
{
|
{
|
||||||
ec_ioctl_sc_state_t data;
|
ec_ioctl_sc_state_t data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
data.config_index = sc->index;
|
data.config_index = sc->index;
|
||||||
data.state = state;
|
data.state = state;
|
||||||
|
|
||||||
if (ioctl(sc->master->fd, EC_IOCTL_SC_STATE, &data) == -1) {
|
ret = ioctl(sc->master->fd, EC_IOCTL_SC_STATE, &data);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to get slave configuration state: %s\n",
|
fprintf(stderr, "Failed to get slave configuration state: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -535,6 +561,7 @@ int ecrt_slave_config_idn(ec_slave_config_t *sc, uint8_t drive_no,
|
||||||
uint16_t idn, ec_al_state_t al_state, const uint8_t *data, size_t size)
|
uint16_t idn, ec_al_state_t al_state, const uint8_t *data, size_t size)
|
||||||
{
|
{
|
||||||
ec_ioctl_sc_idn_t io;
|
ec_ioctl_sc_idn_t io;
|
||||||
|
int ret;
|
||||||
|
|
||||||
io.config_index = sc->index;
|
io.config_index = sc->index;
|
||||||
io.drive_no = drive_no;
|
io.drive_no = drive_no;
|
||||||
|
|
@ -543,9 +570,11 @@ int ecrt_slave_config_idn(ec_slave_config_t *sc, uint8_t drive_no,
|
||||||
io.data = data;
|
io.data = data;
|
||||||
io.size = size;
|
io.size = size;
|
||||||
|
|
||||||
if (ioctl(sc->master->fd, EC_IOCTL_SC_IDN, &io) == -1) {
|
ret = ioctl(sc->master->fd, EC_IOCTL_SC_IDN, &io);
|
||||||
fprintf(stderr, "Failed to configure IDN.\n");
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
return -1; // FIXME
|
fprintf(stderr, "Failed to configure IDN: %s\n",
|
||||||
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
|
return -EC_IOCTL_ERRNO(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
*
|
*
|
||||||
* $Id$
|
* $Id$
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006-2009 Florian Pose, Ingenieurgemeinschaft IgH
|
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||||
*
|
*
|
||||||
* This file is part of the IgH EtherCAT master userspace library.
|
* This file is part of the IgH EtherCAT master userspace library.
|
||||||
*
|
*
|
||||||
|
|
@ -35,15 +35,13 @@
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "ioctl.h"
|
||||||
#include "voe_handler.h"
|
#include "voe_handler.h"
|
||||||
#include "slave_config.h"
|
#include "slave_config.h"
|
||||||
#include "master.h"
|
#include "master.h"
|
||||||
#include "master/ioctl.h"
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
@ -60,16 +58,17 @@ void ecrt_voe_handler_send_header(ec_voe_handler_t *voe, uint32_t vendor_id,
|
||||||
uint16_t vendor_type)
|
uint16_t vendor_type)
|
||||||
{
|
{
|
||||||
ec_ioctl_voe_t data;
|
ec_ioctl_voe_t data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
data.config_index = voe->config->index;
|
data.config_index = voe->config->index;
|
||||||
data.voe_index = voe->index;
|
data.voe_index = voe->index;
|
||||||
data.vendor_id = &vendor_id;
|
data.vendor_id = &vendor_id;
|
||||||
data.vendor_type = &vendor_type;
|
data.vendor_type = &vendor_type;
|
||||||
|
|
||||||
if (ioctl(voe->config->master->fd,
|
ret = ioctl(voe->config->master->fd, EC_IOCTL_VOE_SEND_HEADER, &data);
|
||||||
EC_IOCTL_VOE_SEND_HEADER, &data) == -1) {
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to set VoE send header: %s\n",
|
fprintf(stderr, "Failed to set VoE send header: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -79,16 +78,17 @@ void ecrt_voe_handler_received_header(const ec_voe_handler_t *voe,
|
||||||
uint32_t *vendor_id, uint16_t *vendor_type)
|
uint32_t *vendor_id, uint16_t *vendor_type)
|
||||||
{
|
{
|
||||||
ec_ioctl_voe_t data;
|
ec_ioctl_voe_t data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
data.config_index = voe->config->index;
|
data.config_index = voe->config->index;
|
||||||
data.voe_index = voe->index;
|
data.voe_index = voe->index;
|
||||||
data.vendor_id = vendor_id;
|
data.vendor_id = vendor_id;
|
||||||
data.vendor_type = vendor_type;
|
data.vendor_type = vendor_type;
|
||||||
|
|
||||||
if (ioctl(voe->config->master->fd,
|
ret = ioctl(voe->config->master->fd, EC_IOCTL_VOE_REC_HEADER, &data);
|
||||||
EC_IOCTL_VOE_REC_HEADER, &data) == -1) {
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to get received VoE header: %s\n",
|
fprintf(stderr, "Failed to get received VoE header: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -111,13 +111,15 @@ size_t ecrt_voe_handler_data_size(const ec_voe_handler_t *voe)
|
||||||
void ecrt_voe_handler_read(ec_voe_handler_t *voe)
|
void ecrt_voe_handler_read(ec_voe_handler_t *voe)
|
||||||
{
|
{
|
||||||
ec_ioctl_voe_t data;
|
ec_ioctl_voe_t data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
data.config_index = voe->config->index;
|
data.config_index = voe->config->index;
|
||||||
data.voe_index = voe->index;
|
data.voe_index = voe->index;
|
||||||
|
|
||||||
if (ioctl(voe->config->master->fd, EC_IOCTL_VOE_READ, &data) == -1) {
|
ret = ioctl(voe->config->master->fd, EC_IOCTL_VOE_READ, &data);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to initiate VoE reading: %s\n",
|
fprintf(stderr, "Failed to initiate VoE reading: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -126,14 +128,15 @@ void ecrt_voe_handler_read(ec_voe_handler_t *voe)
|
||||||
void ecrt_voe_handler_read_nosync(ec_voe_handler_t *voe)
|
void ecrt_voe_handler_read_nosync(ec_voe_handler_t *voe)
|
||||||
{
|
{
|
||||||
ec_ioctl_voe_t data;
|
ec_ioctl_voe_t data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
data.config_index = voe->config->index;
|
data.config_index = voe->config->index;
|
||||||
data.voe_index = voe->index;
|
data.voe_index = voe->index;
|
||||||
|
|
||||||
if (ioctl(voe->config->master->fd,
|
ret = ioctl(voe->config->master->fd, EC_IOCTL_VOE_READ_NOSYNC, &data);
|
||||||
EC_IOCTL_VOE_READ_NOSYNC, &data) == -1) {
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to initiate VoE reading: %s\n",
|
fprintf(stderr, "Failed to initiate VoE reading: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -142,15 +145,17 @@ void ecrt_voe_handler_read_nosync(ec_voe_handler_t *voe)
|
||||||
void ecrt_voe_handler_write(ec_voe_handler_t *voe, size_t size)
|
void ecrt_voe_handler_write(ec_voe_handler_t *voe, size_t size)
|
||||||
{
|
{
|
||||||
ec_ioctl_voe_t data;
|
ec_ioctl_voe_t data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
data.config_index = voe->config->index;
|
data.config_index = voe->config->index;
|
||||||
data.voe_index = voe->index;
|
data.voe_index = voe->index;
|
||||||
data.size = size;
|
data.size = size;
|
||||||
data.data = voe->data;
|
data.data = voe->data;
|
||||||
|
|
||||||
if (ioctl(voe->config->master->fd, EC_IOCTL_VOE_WRITE, &data) == -1) {
|
ret = ioctl(voe->config->master->fd, EC_IOCTL_VOE_WRITE, &data);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to initiate VoE writing: %s\n",
|
fprintf(stderr, "Failed to initiate VoE writing: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -159,13 +164,15 @@ void ecrt_voe_handler_write(ec_voe_handler_t *voe, size_t size)
|
||||||
ec_request_state_t ecrt_voe_handler_execute(ec_voe_handler_t *voe)
|
ec_request_state_t ecrt_voe_handler_execute(ec_voe_handler_t *voe)
|
||||||
{
|
{
|
||||||
ec_ioctl_voe_t data;
|
ec_ioctl_voe_t data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
data.config_index = voe->config->index;
|
data.config_index = voe->config->index;
|
||||||
data.voe_index = voe->index;
|
data.voe_index = voe->index;
|
||||||
|
|
||||||
if (ioctl(voe->config->master->fd, EC_IOCTL_VOE_EXEC, &data) == -1) {
|
ret = ioctl(voe->config->master->fd, EC_IOCTL_VOE_EXEC, &data);
|
||||||
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
fprintf(stderr, "Failed to execute VoE handler: %s\n",
|
fprintf(stderr, "Failed to execute VoE handler: %s\n",
|
||||||
strerror(errno));
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
return EC_REQUEST_ERROR;
|
return EC_REQUEST_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -178,8 +185,10 @@ ec_request_state_t ecrt_voe_handler_execute(ec_voe_handler_t *voe)
|
||||||
|
|
||||||
data.data = voe->data;
|
data.data = voe->data;
|
||||||
|
|
||||||
if (ioctl(voe->config->master->fd, EC_IOCTL_VOE_DATA, &data) == -1) {
|
ret = ioctl(voe->config->master->fd, EC_IOCTL_VOE_DATA, &data);
|
||||||
fprintf(stderr, "Failed to get VoE data: %s\n", strerror(errno));
|
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||||
|
fprintf(stderr, "Failed to get VoE data: %s\n",
|
||||||
|
strerror(EC_IOCTL_ERRNO(ret)));
|
||||||
return EC_REQUEST_ERROR;
|
return EC_REQUEST_ERROR;
|
||||||
}
|
}
|
||||||
voe->data_size = data.size;
|
voe->data_size = data.size;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
# $Id$
|
# $Id$
|
||||||
#
|
#
|
||||||
# Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
|
# Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||||
#
|
#
|
||||||
# This file is part of the IgH EtherCAT Master.
|
# This file is part of the IgH EtherCAT Master.
|
||||||
#
|
#
|
||||||
|
|
@ -52,6 +52,7 @@ ec_master-objs := \
|
||||||
fsm_slave_config.o \
|
fsm_slave_config.o \
|
||||||
fsm_slave_scan.o \
|
fsm_slave_scan.o \
|
||||||
fsm_soe.o \
|
fsm_soe.o \
|
||||||
|
ioctl.o \
|
||||||
mailbox.o \
|
mailbox.o \
|
||||||
master.o \
|
master.o \
|
||||||
module.o \
|
module.o \
|
||||||
|
|
@ -70,12 +71,30 @@ ec_master-objs := \
|
||||||
voe_handler.o
|
voe_handler.o
|
||||||
|
|
||||||
ifeq (@ENABLE_EOE@,1)
|
ifeq (@ENABLE_EOE@,1)
|
||||||
ec_master-objs += ethernet.o
|
ec_master-objs += ethernet.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq (@ENABLE_DEBUG_IF@,1)
|
ifeq (@ENABLE_DEBUG_IF@,1)
|
||||||
ec_master-objs += debug.o
|
ec_master-objs += debug.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq (@ENABLE_RTDM@,1)
|
||||||
|
|
||||||
|
ec_master-objs += rtdm.o
|
||||||
|
|
||||||
|
ifeq (@ENABLE_XENOMAI@, 1)
|
||||||
|
CFLAGS_rtdm.o := -I@XENOMAI_DIR@/include
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq (@ENABLE_RTAI@, 1)
|
||||||
|
CFLAGS_rtdm.o := -I@RTAI_DIR@/include
|
||||||
|
endif
|
||||||
|
|
||||||
|
ec_master-objs += rtdm-ioctl.o
|
||||||
|
CFLAGS_rtdm-ioctl.o := -DEC_IOCTL_RTDM
|
||||||
|
|
||||||
|
endif # ENABLE_RTDM
|
||||||
|
|
||||||
REV := $(shell if test -s $(src)/../revision; then \
|
REV := $(shell if test -s $(src)/../revision; then \
|
||||||
cat $(src)/../revision; \
|
cat $(src)/../revision; \
|
||||||
else \
|
else \
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
# $Id$
|
# $Id$
|
||||||
#
|
#
|
||||||
# Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
|
# Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||||
#
|
#
|
||||||
# This file is part of the IgH EtherCAT Master.
|
# This file is part of the IgH EtherCAT Master.
|
||||||
#
|
#
|
||||||
|
|
@ -32,7 +32,7 @@ noinst_HEADERS = \
|
||||||
cdev.c cdev.h \
|
cdev.c cdev.h \
|
||||||
datagram.c datagram.h \
|
datagram.c datagram.h \
|
||||||
datagram_pair.c datagram_pair.h \
|
datagram_pair.c datagram_pair.h \
|
||||||
debug.c debug.h \
|
debug.c debug.h \
|
||||||
device.c device.h \
|
device.c device.h \
|
||||||
domain.c domain.h \
|
domain.c domain.h \
|
||||||
doxygen.c \
|
doxygen.c \
|
||||||
|
|
@ -52,13 +52,15 @@ noinst_HEADERS = \
|
||||||
fsm_slave_scan.c fsm_slave_scan.h \
|
fsm_slave_scan.c fsm_slave_scan.h \
|
||||||
fsm_soe.c fsm_soe.h \
|
fsm_soe.c fsm_soe.h \
|
||||||
globals.h \
|
globals.h \
|
||||||
ioctl.h \
|
ioctl.c ioctl.h \
|
||||||
mailbox.c mailbox.h \
|
mailbox.c mailbox.h \
|
||||||
master.c master.h \
|
master.c master.h \
|
||||||
module.c \
|
module.c \
|
||||||
pdo.c pdo.h \
|
pdo.c pdo.h \
|
||||||
pdo_entry.c pdo_entry.h \
|
pdo_entry.c pdo_entry.h \
|
||||||
pdo_list.c pdo_list.h \
|
pdo_list.c pdo_list.h \
|
||||||
|
rtdm-ioctl.c \
|
||||||
|
rtdm.c rtdm.h \
|
||||||
sdo.c sdo.h \
|
sdo.c sdo.h \
|
||||||
sdo_entry.c sdo_entry.h \
|
sdo_entry.c sdo_entry.h \
|
||||||
sdo_request.c sdo_request.h \
|
sdo_request.c sdo_request.h \
|
||||||
|
|
|
||||||
3745
master/cdev.c
3745
master/cdev.c
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -2,7 +2,7 @@
|
||||||
*
|
*
|
||||||
* $Id$
|
* $Id$
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
|
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||||
*
|
*
|
||||||
* This file is part of the IgH EtherCAT Master.
|
* This file is part of the IgH EtherCAT Master.
|
||||||
*
|
*
|
||||||
|
|
@ -96,7 +96,7 @@
|
||||||
#define EC_IOCTL_REQUEST EC_IO(0x1e)
|
#define EC_IOCTL_REQUEST EC_IO(0x1e)
|
||||||
#define EC_IOCTL_CREATE_DOMAIN EC_IO(0x1f)
|
#define EC_IOCTL_CREATE_DOMAIN EC_IO(0x1f)
|
||||||
#define EC_IOCTL_CREATE_SLAVE_CONFIG EC_IOWR(0x20, ec_ioctl_config_t)
|
#define EC_IOCTL_CREATE_SLAVE_CONFIG EC_IOWR(0x20, ec_ioctl_config_t)
|
||||||
#define EC_IOCTL_ACTIVATE EC_IOR(0x21, size_t)
|
#define EC_IOCTL_ACTIVATE EC_IOR(0x21, ec_ioctl_master_activate_t)
|
||||||
#define EC_IOCTL_DEACTIVATE EC_IO(0x22)
|
#define EC_IOCTL_DEACTIVATE EC_IO(0x22)
|
||||||
#define EC_IOCTL_SEND EC_IO(0x23)
|
#define EC_IOCTL_SEND EC_IO(0x23)
|
||||||
#define EC_IOCTL_RECEIVE EC_IO(0x24)
|
#define EC_IOCTL_RECEIVE EC_IO(0x24)
|
||||||
|
|
@ -573,6 +573,14 @@ typedef struct {
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
// outputs
|
||||||
|
void *process_data;
|
||||||
|
size_t process_data_size;
|
||||||
|
} ec_ioctl_master_activate_t;
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
// inputs
|
// inputs
|
||||||
uint32_t config_index;
|
uint32_t config_index;
|
||||||
|
|
@ -689,6 +697,32 @@ typedef struct {
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
|
||||||
|
/** Context data structure for file handles.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
unsigned int writable; /**< Device was opened with write permission. */
|
||||||
|
unsigned int requested; /**< Master was requested via this file handle. */
|
||||||
|
uint8_t *process_data; /**< Total process data area. */
|
||||||
|
size_t process_data_size; /**< Size of the \a process_data. */
|
||||||
|
} ec_ioctl_context_t;
|
||||||
|
|
||||||
|
long ec_ioctl(ec_master_t *, ec_ioctl_context_t *, unsigned int,
|
||||||
|
void __user *);
|
||||||
|
|
||||||
|
#ifdef EC_RTDM
|
||||||
|
|
||||||
|
long ec_ioctl_rtdm(ec_master_t *, ec_ioctl_context_t *, unsigned int,
|
||||||
|
void __user *);
|
||||||
|
int ec_rtdm_mmap(ec_ioctl_context_t *, void **);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
/** \endcond */
|
/** \endcond */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
*
|
*
|
||||||
* $Id$
|
* $Id$
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
|
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||||
*
|
*
|
||||||
* This file is part of the IgH EtherCAT Master.
|
* This file is part of the IgH EtherCAT Master.
|
||||||
*
|
*
|
||||||
|
|
@ -298,8 +298,24 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT master */
|
||||||
goto out_clear_cdev;
|
goto out_clear_cdev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef EC_RTDM
|
||||||
|
// init RTDM device
|
||||||
|
ret = ec_rtdm_dev_init(&master->rtdm_dev, master);
|
||||||
|
if (ret) {
|
||||||
|
goto out_unregister_class_device;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
#ifdef EC_RTDM
|
||||||
|
out_unregister_class_device:
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
|
||||||
|
device_unregister(master->class_device);
|
||||||
|
#else
|
||||||
|
class_device_unregister(master->class_device);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
out_clear_cdev:
|
out_clear_cdev:
|
||||||
ec_cdev_clear(&master->cdev);
|
ec_cdev_clear(&master->cdev);
|
||||||
out_clear_sync_mon:
|
out_clear_sync_mon:
|
||||||
|
|
@ -327,6 +343,10 @@ void ec_master_clear(
|
||||||
ec_master_t *master /**< EtherCAT master */
|
ec_master_t *master /**< EtherCAT master */
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
#ifdef EC_RTDM
|
||||||
|
ec_rtdm_dev_clear(&master->rtdm_dev);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
|
||||||
device_unregister(master->class_device);
|
device_unregister(master->class_device);
|
||||||
#else
|
#else
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
*
|
*
|
||||||
* $Id$
|
* $Id$
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
|
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
|
||||||
*
|
*
|
||||||
* This file is part of the IgH EtherCAT Master.
|
* This file is part of the IgH EtherCAT Master.
|
||||||
*
|
*
|
||||||
|
|
@ -55,6 +55,10 @@
|
||||||
#include "fsm_master.h"
|
#include "fsm_master.h"
|
||||||
#include "cdev.h"
|
#include "cdev.h"
|
||||||
|
|
||||||
|
#ifdef EC_RTDM
|
||||||
|
#include "rtdm.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
/** Convenience macro for printing master-specific information to syslog.
|
/** Convenience macro for printing master-specific information to syslog.
|
||||||
|
|
@ -183,6 +187,10 @@ struct ec_master {
|
||||||
struct class_device *class_device; /**< Master class device. */
|
struct class_device *class_device; /**< Master class device. */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef EC_RTDM
|
||||||
|
ec_rtdm_dev_t rtdm_dev; /**< RTDM device. */
|
||||||
|
#endif
|
||||||
|
|
||||||
struct semaphore master_sem; /**< Master semaphore. */
|
struct semaphore master_sem; /**< Master semaphore. */
|
||||||
|
|
||||||
ec_device_t devices[EC_NUM_DEVICES]; /**< EtherCAT devices. */
|
ec_device_t devices[EC_NUM_DEVICES]; /**< EtherCAT devices. */
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
ioctl.c
|
||||||
|
|
@ -0,0 +1,218 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009-2010 Moehwald GmbH B. Benner
|
||||||
|
* 2011 IgH Andreas Stewering-Bone
|
||||||
|
* 2012 Florian Pose <fp@igh-essen.com>
|
||||||
|
*
|
||||||
|
* 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 as published
|
||||||
|
* by the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/mman.h>
|
||||||
|
|
||||||
|
#include <rtdm/rtdm_driver.h>
|
||||||
|
|
||||||
|
#include "master.h"
|
||||||
|
#include "ioctl.h"
|
||||||
|
#include "rtdm.h"
|
||||||
|
|
||||||
|
/** Set to 1 to enable device operations debugging.
|
||||||
|
*/
|
||||||
|
#define DEBUG 0
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/** Context structure for an open RTDM file handle.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
rtdm_user_info_t *user_info;
|
||||||
|
ec_ioctl_context_t ioctl_ctx;
|
||||||
|
} ec_rtdm_context_t;
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
int ec_rtdm_open(struct rtdm_dev_context *, rtdm_user_info_t *, int);
|
||||||
|
int ec_rtdm_close(struct rtdm_dev_context *, rtdm_user_info_t *);
|
||||||
|
int ec_rtdm_ioctl(struct rtdm_dev_context *, rtdm_user_info_t *,
|
||||||
|
unsigned int, void __user *);
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
int ec_rtdm_dev_init(
|
||||||
|
ec_rtdm_dev_t *rtdm_dev,
|
||||||
|
ec_master_t *master
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
rtdm_dev->master = master;
|
||||||
|
|
||||||
|
rtdm_dev->dev = kzalloc(sizeof(struct rtdm_device), GFP_KERNEL);
|
||||||
|
if (!rtdm_dev->dev) {
|
||||||
|
EC_MASTER_ERR(master, "Failed to reserve memory for RTDM device.\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtdm_dev->dev->struct_version = RTDM_DEVICE_STRUCT_VER;
|
||||||
|
rtdm_dev->dev->device_flags = RTDM_NAMED_DEVICE;
|
||||||
|
rtdm_dev->dev->context_size = sizeof(ec_rtdm_context_t);
|
||||||
|
snprintf(rtdm_dev->dev->device_name, RTDM_MAX_DEVNAME_LEN,
|
||||||
|
"EtherCAT%u", master->index);
|
||||||
|
rtdm_dev->dev->open_nrt = ec_rtdm_open;
|
||||||
|
rtdm_dev->dev->ops.close_nrt = ec_rtdm_close;
|
||||||
|
rtdm_dev->dev->ops.ioctl_rt = ec_rtdm_ioctl;
|
||||||
|
rtdm_dev->dev->ops.ioctl_nrt = ec_rtdm_ioctl;
|
||||||
|
rtdm_dev->dev->device_class = RTDM_CLASS_EXPERIMENTAL;
|
||||||
|
rtdm_dev->dev->device_sub_class = 222;
|
||||||
|
rtdm_dev->dev->driver_name = "EtherCAT";
|
||||||
|
rtdm_dev->dev->driver_version = RTDM_DRIVER_VER(1, 0, 2);
|
||||||
|
rtdm_dev->dev->peripheral_name = rtdm_dev->dev->device_name;
|
||||||
|
rtdm_dev->dev->provider_name = "EtherLab Community";
|
||||||
|
rtdm_dev->dev->proc_name = rtdm_dev->dev->device_name;
|
||||||
|
rtdm_dev->dev->device_data = rtdm_dev; /* pointer to parent */
|
||||||
|
|
||||||
|
EC_MASTER_INFO(master, "Registering RTDM device %s.\n",
|
||||||
|
rtdm_dev->dev->driver_name);
|
||||||
|
ret = rtdm_dev_register(rtdm_dev->dev);
|
||||||
|
if (ret) {
|
||||||
|
EC_MASTER_ERR(master, "Initialization of RTDM interface failed"
|
||||||
|
" (return value %i).\n", ret);
|
||||||
|
kfree(rtdm_dev->dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
void ec_rtdm_dev_clear(
|
||||||
|
ec_rtdm_dev_t *rtdm_dev
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
EC_MASTER_INFO(rtdm_dev->master, "Unregistering RTDM device %s.\n",
|
||||||
|
rtdm_dev->dev->driver_name);
|
||||||
|
ret = rtdm_dev_unregister(rtdm_dev->dev, 1000 /* poll delay [ms] */);
|
||||||
|
if (ret < 0) {
|
||||||
|
EC_MASTER_WARN(rtdm_dev->master,
|
||||||
|
"Failed to unregister RTDM device (code %i).\n", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
kfree(rtdm_dev->dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/** Driver open.
|
||||||
|
*/
|
||||||
|
int ec_rtdm_open(
|
||||||
|
struct rtdm_dev_context *context,
|
||||||
|
rtdm_user_info_t *user_info,
|
||||||
|
int oflags
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ec_rtdm_context_t *ctx = (ec_rtdm_context_t *) context->dev_private;
|
||||||
|
#if DEBUG
|
||||||
|
ec_rtdm_dev_t *rtdm_dev = (ec_rtdm_dev_t *) context->device->device_data;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ctx->user_info = user_info;
|
||||||
|
ctx->ioctl_ctx.writable = oflags & O_WRONLY || oflags & O_RDWR;
|
||||||
|
ctx->ioctl_ctx.requested = 0;
|
||||||
|
ctx->ioctl_ctx.process_data = NULL;
|
||||||
|
ctx->ioctl_ctx.process_data_size = 0;
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
EC_MASTER_INFO(rtdm_dev->master, "RTDM device %s opened.\n",
|
||||||
|
context->device->device_name);
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/** Driver close.
|
||||||
|
*/
|
||||||
|
int ec_rtdm_close(struct rtdm_dev_context *context,
|
||||||
|
rtdm_user_info_t *user_info)
|
||||||
|
{
|
||||||
|
ec_rtdm_context_t *ctx = (ec_rtdm_context_t *) context->dev_private;
|
||||||
|
ec_rtdm_dev_t *rtdm_dev = (ec_rtdm_dev_t *) context->device->device_data;
|
||||||
|
|
||||||
|
if (ctx->ioctl_ctx.requested) {
|
||||||
|
ecrt_release_master(rtdm_dev->master);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
EC_MASTER_INFO(rtdm_dev->master, "RTDM device %s closed.\n",
|
||||||
|
context->device->device_name);
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/** Driver ioctl.
|
||||||
|
*/
|
||||||
|
int ec_rtdm_ioctl(
|
||||||
|
struct rtdm_dev_context *context, /**< Context. */
|
||||||
|
rtdm_user_info_t *user_info, /**< User data. */
|
||||||
|
unsigned int request, /**< Request. */
|
||||||
|
void __user *arg /**< Argument. */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ec_rtdm_context_t *ctx = (ec_rtdm_context_t *) context->dev_private;
|
||||||
|
ec_rtdm_dev_t *rtdm_dev = (ec_rtdm_dev_t *) context->device->device_data;
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
EC_MASTER_INFO(rtdm_dev->master, "ioctl(request = %u, ctl = %02x)"
|
||||||
|
" on RTDM device %s.\n", request, _IOC_NR(request),
|
||||||
|
context->device->device_name);
|
||||||
|
#endif
|
||||||
|
return ec_ioctl_rtdm(rtdm_dev->master, &ctx->ioctl_ctx, request, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/** Memory-map process data to user space.
|
||||||
|
*/
|
||||||
|
int ec_rtdm_mmap(ec_ioctl_context_t *ioctl_ctx, void **user_address)
|
||||||
|
{
|
||||||
|
ec_rtdm_context_t *ctx =
|
||||||
|
container_of(ioctl_ctx, ec_rtdm_context_t, ioctl_ctx);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = rtdm_mmap_to_user(ctx->user_info,
|
||||||
|
ioctl_ctx->process_data, ioctl_ctx->process_data_size,
|
||||||
|
PROT_READ | PROT_WRITE,
|
||||||
|
user_address,
|
||||||
|
NULL, NULL);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Florian Pose <fp@igh-essen.com>
|
||||||
|
*
|
||||||
|
* 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 as published
|
||||||
|
* by the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __EC_RTDM_H__
|
||||||
|
#define __EC_RTDM_H__
|
||||||
|
|
||||||
|
#include "../include/ecrt.h" /* ec_master_t */
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
struct rtdm_device;
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
typedef struct ec_rtdm_dev {
|
||||||
|
ec_master_t *master;
|
||||||
|
struct rtdm_device *dev;
|
||||||
|
} ec_rtdm_dev_t;
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
int ec_rtdm_dev_init(ec_rtdm_dev_t *, ec_master_t *);
|
||||||
|
void ec_rtdm_dev_clear(ec_rtdm_dev_t *);
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#endif
|
||||||
Loading…
Reference in New Issue