Removed MSR example; adapted RTAI example; README files for examples.
This commit is contained in:
parent
8265fb115f
commit
93a66a3573
11
TODO
11
TODO
|
|
@ -8,22 +8,22 @@ $Id$
|
|||
|
||||
Version 1.4.0:
|
||||
|
||||
* Race in jiffies frame timeout.
|
||||
* Move EC_NUM_SYNCS define to ecrt.h.
|
||||
* Read Pdo mapping for unknown Pdos before configuring it.
|
||||
* Read Pdo mapping for unknown Pdos before configuring them.
|
||||
* Attach Pdo names from SII or Coe dictioary to Pdos read via CoE.
|
||||
* Make scanning and configuration run parallel (each).
|
||||
* Adapt remaining examples.
|
||||
* READMEs for examples.
|
||||
* Update documentation.
|
||||
* Add -a and -p switches for 'ethercat config' command.
|
||||
* Race in jiffies frame timeout.
|
||||
* Add a -n (numeric) switch to ethercat command.
|
||||
* Make verbose and quite flags a master property.
|
||||
* File access over EtherCAT (FoE).
|
||||
* Allow master requesting when in ORPHANED phase
|
||||
* Get original driver for r8169.
|
||||
* Distributed clocks.
|
||||
|
||||
Future issues:
|
||||
|
||||
* Distributed clocks.
|
||||
* Move master threads, slave handlers and state machines into a user
|
||||
space daemon.
|
||||
* Implement user space realtime interface via cdev.
|
||||
|
|
@ -35,7 +35,6 @@ Future issues:
|
|||
* Optimize alignment of process data.
|
||||
* Redundancy with 2 network adapters.
|
||||
* Interface/buffers for asynchronous domain IO.
|
||||
* Add a -n (numeric) switch to ethercat command.
|
||||
|
||||
Smaller issues:
|
||||
|
||||
|
|
|
|||
32
configure.ac
32
configure.ac
|
|
@ -383,36 +383,6 @@ fi
|
|||
|
||||
AC_SUBST(RTAI_DIR,[$rtaidir])
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# MSR path (optional)
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
AC_ARG_WITH([msr-dir],
|
||||
AC_HELP_STRING(
|
||||
[--with-msr-dir=<DIR>],
|
||||
[MSR path (only for MSR example)]
|
||||
),
|
||||
[
|
||||
msrdir=[$withval]
|
||||
],
|
||||
[
|
||||
msrdir=""
|
||||
]
|
||||
)
|
||||
|
||||
AC_MSG_CHECKING([for MSR path])
|
||||
|
||||
if test -z "${msrdir}"; then
|
||||
AC_MSG_RESULT([not specified.])
|
||||
else
|
||||
if test \! -r ${msrdir}/include/msr.h; then
|
||||
AC_MSG_ERROR([no MSR installation found in ${msrdir}!])
|
||||
fi
|
||||
AC_MSG_RESULT([$msrdir])
|
||||
fi
|
||||
|
||||
AC_SUBST(MSR_DIR,[$msrdir])
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Debug interface
|
||||
#------------------------------------------------------------------------------
|
||||
|
|
@ -526,8 +496,6 @@ AC_CONFIG_FILES([
|
|||
examples/Makefile
|
||||
examples/mini/Kbuild
|
||||
examples/mini/Makefile
|
||||
examples/msr/Kbuild
|
||||
examples/msr/Makefile
|
||||
examples/rtai/Kbuild
|
||||
examples/rtai/Makefile
|
||||
include/Makefile
|
||||
|
|
|
|||
|
|
@ -31,6 +31,6 @@
|
|||
#
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
DIST_SUBDIRS = mini rtai msr
|
||||
DIST_SUBDIRS = mini rtai
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
-------------------------------------------------------------------------------
|
||||
|
||||
$Id$
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
This is a minimal example module for the use of the EtherCAT master realtime
|
||||
interface. It uses a kernel timer to generate a cyclic task.
|
||||
|
||||
Most probably you'll have different EtherCAT slaves present. Try adjusting the
|
||||
section "process data" in mini.c to your bus configuration.
|
||||
|
||||
There are some features that can be disabled by commenting out the respective
|
||||
defines at the head of mini.c.
|
||||
|
||||
---
|
||||
|
||||
To build the example module, call:
|
||||
|
||||
make modules
|
||||
|
||||
To run it, call:
|
||||
|
||||
insmod ec_mini.ko
|
||||
|
||||
...and watch the system logs for the outputs.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
|
@ -43,16 +43,13 @@
|
|||
// Module parameters
|
||||
#define FREQUENCY 100
|
||||
|
||||
// Optional features
|
||||
// Optional features (comment to disable)
|
||||
#define CONFIGURE_PDOS
|
||||
#define EXTERNAL_MEMORY
|
||||
#define SDO_ACCESS
|
||||
|
||||
#define PFX "ec_mini: "
|
||||
|
||||
#define AnaInPos 0, 1
|
||||
#define DigOutPos 0, 3
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
// EtherCAT
|
||||
|
|
@ -66,28 +63,32 @@ static ec_domain_state_t domain1_state = {};
|
|||
static ec_slave_config_t *sc_ana_in = NULL;
|
||||
static ec_slave_config_state_t sc_ana_in_state = {};
|
||||
|
||||
// Timer
|
||||
static struct timer_list timer;
|
||||
static unsigned int counter = 0;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
// process data
|
||||
static uint8_t *domain1_pd; // process data memory
|
||||
|
||||
static unsigned int off_ana_in; // offsets for Pdo entries
|
||||
static unsigned int off_dig_out;
|
||||
|
||||
static unsigned int blink = 0;
|
||||
#define AnaInSlavePos 0, 1
|
||||
#define DigOutSlavePos 0, 3
|
||||
|
||||
#define Beckhoff_EL2004 0x00000002, 0x07D43052
|
||||
#define Beckhoff_EL3162 0x00000002, 0x0C5A3052
|
||||
|
||||
static unsigned int off_ana_in; // offsets for Pdo entries
|
||||
static unsigned int off_dig_out;
|
||||
|
||||
const static ec_pdo_entry_reg_t domain1_regs[] = {
|
||||
{AnaInPos, Beckhoff_EL3162, 0x3101, 2, &off_ana_in},
|
||||
{DigOutPos, Beckhoff_EL2004, 0x3001, 1, &off_dig_out},
|
||||
{AnaInSlavePos, Beckhoff_EL3162, 0x3101, 2, &off_ana_in},
|
||||
{DigOutSlavePos, Beckhoff_EL2004, 0x3001, 1, &off_dig_out},
|
||||
{}
|
||||
};
|
||||
|
||||
static unsigned int counter = 0;
|
||||
static unsigned int blink = 0;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifdef CONFIGURE_PDOS
|
||||
|
|
@ -312,7 +313,7 @@ int __init init_mini_module(void)
|
|||
}
|
||||
|
||||
if (!(sc_ana_in = ecrt_master_slave_config(
|
||||
master, AnaInPos, Beckhoff_EL3162))) {
|
||||
master, AnaInSlavePos, Beckhoff_EL3162))) {
|
||||
printk(KERN_ERR PFX "Failed to get slave configuration.\n");
|
||||
goto out_release_master;
|
||||
}
|
||||
|
|
@ -324,7 +325,8 @@ int __init init_mini_module(void)
|
|||
goto out_release_master;
|
||||
}
|
||||
|
||||
if (!(sc = ecrt_master_slave_config(master, DigOutPos, Beckhoff_EL2004))) {
|
||||
if (!(sc = ecrt_master_slave_config(
|
||||
master, DigOutSlavePos, Beckhoff_EL2004))) {
|
||||
printk(KERN_ERR PFX "Failed to get slave configuration.\n");
|
||||
goto out_release_master;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,61 +0,0 @@
|
|||
#------------------------------------------------------------------------------
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
# Copyright (C) 2006 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
|
||||
# as published by the Free Software Foundation; either version 2 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# 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 right to use EtherCAT Technology is granted and comes free of
|
||||
# charge under condition of compatibility of product made by
|
||||
# Licensee. People intending to distribute/sell products based on the
|
||||
# code, have to sign an agreement to guarantee that products using
|
||||
# software based on IgH EtherCAT master stay compatible with the actual
|
||||
# EtherCAT specification (which are released themselves as an open
|
||||
# standard) as the (only) precondition to have the right to use EtherCAT
|
||||
# Technology, IP and trade marks.
|
||||
#
|
||||
# vi: syntax=make
|
||||
#
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
MODULE := ec_msr_sample
|
||||
|
||||
obj-m := $(MODULE).o
|
||||
|
||||
$(MODULE)-objs := \
|
||||
msr_sample.o \
|
||||
rt_lib/msr-core/msr_lists.o \
|
||||
rt_lib/msr-core/msr_main.o \
|
||||
rt_lib/msr-core/msr_charbuf.o \
|
||||
rt_lib/msr-core/msr_reg.o \
|
||||
rt_lib/msr-core/msr_interpreter.o \
|
||||
rt_lib/msr-core/msr_messages.o \
|
||||
rt_lib/msr-core/msr_proc.o \
|
||||
rt_lib/msr-core/msr_error_reg.o \
|
||||
rt_lib/msr-utils/msr_utils.o \
|
||||
rt_lib/msr-utils/msr_time.o \
|
||||
rt_lib/msr-math/msr_base64.o \
|
||||
rt_lib/msr-math/msr_hex_bin.o \
|
||||
libm.o
|
||||
|
||||
EXTRA_CFLAGS := \
|
||||
-I@MSR_DIR@/include \
|
||||
-I@RTAI_DIR@/include \
|
||||
-D_SIMULATION -mhard-float
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
#------------------------------------------------------------------------------
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
# Copyright (C) 2006 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
|
||||
# as published by the Free Software Foundation; either version 2 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# 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 right to use EtherCAT Technology is granted and comes free of
|
||||
# charge under condition of compatibility of product made by
|
||||
# Licensee. People intending to distribute/sell products based on the
|
||||
# code, have to sign an agreement to guarantee that products using
|
||||
# software based on IgH EtherCAT master stay compatible with the actual
|
||||
# EtherCAT specification (which are released themselves as an open
|
||||
# standard) as the (only) precondition to have the right to use EtherCAT
|
||||
# Technology, IP and trade marks.
|
||||
#
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
EXTRA_DIST = \
|
||||
Kbuild.in \
|
||||
libm.o_shipped \
|
||||
msr_sample.c \
|
||||
msrserv.pl \
|
||||
init.sh
|
||||
|
||||
BUILT_SOURCES = \
|
||||
Kbuild
|
||||
|
||||
modules:
|
||||
$(MAKE) -C "$(LINUX_SOURCE_DIR)" M="@abs_srcdir@" modules
|
||||
|
||||
modules_install:
|
||||
mkdir -p $(DESTDIR)$(LINUX_MOD_PATH)
|
||||
cp $(srcdir)/ec_msr_sample.ko $(DESTDIR)$(LINUX_MOD_PATH)
|
||||
|
||||
clean-local:
|
||||
$(MAKE) -C "$(LINUX_SOURCE_DIR)" M="@abs_srcdir@" clean
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
|
@ -1,129 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
#
|
||||
# MSR Init Script
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
### BEGIN INIT INFO
|
||||
# Provides: msr
|
||||
# Required-Start: $local_fs $syslog $network
|
||||
# Should-Start: $time ntp ethercat
|
||||
# Required-Stop: $local_fs $syslog $network
|
||||
# Should-Stop: $time ntp ethercat
|
||||
# Default-Start: 3 5
|
||||
# Default-Stop: 0 1 2 6
|
||||
# Short-Description: MSR module
|
||||
# Description:
|
||||
### END INIT INFO
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# <Customizing>
|
||||
|
||||
NAME="MSR EtherCAT sample"
|
||||
BASE=/opt/etherlab
|
||||
MSR_SERVER=$BASE/bin/msrserv.pl
|
||||
MODULE=ec_msr_sample
|
||||
RTAI_PATH=/usr/realtime
|
||||
RTAI_MODULES="hal up" # sem math
|
||||
DEVICE=msr
|
||||
DEVMASK=664
|
||||
GROUP=users
|
||||
|
||||
# </Customizing>
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
. /etc/rc.status
|
||||
rc_reset
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
echo -n Starting $NAME" "
|
||||
|
||||
# Insert RTAI modules
|
||||
for mod in $RTAI_MODULES; do
|
||||
if ! lsmod | grep -q "^rtai_$mod"; then
|
||||
if ! insmod $RTAI_PATH/modules/rtai_$mod.ko; then
|
||||
/bin/false
|
||||
rc_status -v
|
||||
rc_exit
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Insert realtime module
|
||||
if ! modprobe $MODULE; then
|
||||
/bin/false
|
||||
rc_status -v
|
||||
rc_exit
|
||||
fi
|
||||
|
||||
#sleep 2
|
||||
|
||||
# Create MSR device
|
||||
MAJOR=`cat /proc/devices | awk "\\$2==\"$DEVICE\" {print \\$1}"`
|
||||
rm -f /dev/${DEVICE}
|
||||
mknod /dev/${DEVICE} c $MAJOR 0
|
||||
chgrp $GROUP /dev/${DEVICE}
|
||||
chmod $DEVMASK /dev/${DEVICE}
|
||||
|
||||
#sleep 1
|
||||
|
||||
# Start MSR-Server
|
||||
startproc $MSR_SERVER 1>/dev/null 2>/dev/null
|
||||
rc_status -v
|
||||
;;
|
||||
|
||||
stop)
|
||||
echo -n Shutting down $NAME" "
|
||||
|
||||
if ! killproc $MSR_SERVER; then
|
||||
/bin/false
|
||||
rc_status -v
|
||||
rc_exit
|
||||
fi
|
||||
|
||||
if ! /sbin/rmmod $MODULE; then
|
||||
/bin/false
|
||||
rc_status -v
|
||||
rc_exit
|
||||
fi
|
||||
|
||||
# Remove stale nodes
|
||||
rm -f /dev/${DEVICE} /dev/${DEVICE}0
|
||||
|
||||
rc_status -v
|
||||
;;
|
||||
|
||||
restart)
|
||||
$0 stop || exit 1
|
||||
sleep 1
|
||||
$0 start
|
||||
|
||||
rc_status
|
||||
;;
|
||||
|
||||
status)
|
||||
echo -n "Checking for MSR module: "
|
||||
/sbin/lsmod | grep -q "^$MODULE"
|
||||
rc_status -v
|
||||
|
||||
echo -n "Checking for MSR server: "
|
||||
checkproc $MSR_SERVER
|
||||
rc_status -v
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|status|restart}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
rc_exit
|
||||
|
|
@ -1 +0,0 @@
|
|||
/usr/lib/libm.a
|
||||
|
|
@ -1,230 +0,0 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006 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
|
||||
* as published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* 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 right to use EtherCAT Technology is granted and comes free of
|
||||
* charge under condition of compatibility of product made by
|
||||
* Licensee. People intending to distribute/sell products based on the
|
||||
* code, have to sign an agreement to guarantee that products using
|
||||
* software based on IgH EtherCAT master stay compatible with the actual
|
||||
* EtherCAT specification (which are released themselves as an open
|
||||
* standard) as the (only) precondition to have the right to use EtherCAT
|
||||
* Technology, IP and trade marks.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
// Linux
|
||||
#include <linux/module.h>
|
||||
|
||||
// RTAI
|
||||
#include "rtai_sched.h"
|
||||
#include "rtai_sem.h"
|
||||
|
||||
// RT_lib
|
||||
#include <msr_main.h>
|
||||
#include <msr_reg.h>
|
||||
#include <msr_time.h>
|
||||
|
||||
// EtherCAT
|
||||
#include "../../include/ecrt.h"
|
||||
#include "../../include/ecdb.h"
|
||||
|
||||
#define MSR_ABTASTFREQUENZ 1000
|
||||
|
||||
#define HZREDUCTION (MSR_ABTASTFREQUENZ / HZ)
|
||||
#define TIMERTICKS (1000000000 / MSR_ABTASTFREQUENZ)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
// RTAI
|
||||
RT_TASK task;
|
||||
SEM master_sem;
|
||||
cycles_t t_start = 0, t_critical;
|
||||
|
||||
// EtherCAT
|
||||
ec_master_t *master = NULL;
|
||||
ec_domain_t *domain1 = NULL;
|
||||
|
||||
// raw process data
|
||||
void *r_ana_out;
|
||||
|
||||
// channels
|
||||
double k_ana_out;
|
||||
|
||||
ec_pdo_reg_t domain1_pdos[] = {
|
||||
{"3", Beckhoff_EL4132_Output1, &r_ana_out},
|
||||
{}
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void msr_controller_run(void)
|
||||
{
|
||||
// receive
|
||||
rt_sem_wait(&master_sem);
|
||||
ecrt_master_receive(master);
|
||||
ecrt_domain_process(domain1);
|
||||
rt_sem_signal(&master_sem);
|
||||
|
||||
// Process data
|
||||
EC_WRITE_S16(r_ana_out, k_ana_out / 10.0 * 0x7FFF);
|
||||
|
||||
// Send
|
||||
rt_sem_wait(&master_sem);
|
||||
ecrt_domain_queue(domain1);
|
||||
ecrt_master_run(master);
|
||||
ecrt_master_send(master);
|
||||
rt_sem_signal(&master_sem);
|
||||
|
||||
msr_write_kanal_list();
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void msr_run(long data)
|
||||
{
|
||||
while (1) {
|
||||
t_start = get_cycles();
|
||||
MSR_RTAITHREAD_CODE(msr_controller_run(););
|
||||
rt_task_wait_period();
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int msr_reg(void)
|
||||
{
|
||||
msr_reg_kanal("/ana_out", "", &k_ana_out, TDBL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int request_lock(void *data)
|
||||
{
|
||||
// too close to the next RT cycle: deny access...
|
||||
if (get_cycles() - t_start > t_critical) return -1;
|
||||
|
||||
// allow access
|
||||
rt_sem_wait(&master_sem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void release_lock(void *data)
|
||||
{
|
||||
rt_sem_signal(&master_sem);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int __init init_mod(void)
|
||||
{
|
||||
RTIME ticks;
|
||||
|
||||
printk(KERN_INFO "=== Starting EtherCAT RTAI MSR sample module... ===\n");
|
||||
|
||||
rt_sem_init(&master_sem, 1);
|
||||
t_critical = cpu_khz * 800 / MSR_ABTASTFREQUENZ; // ticks for 80%
|
||||
|
||||
if (msr_rtlib_init(1, MSR_ABTASTFREQUENZ, 10, &msr_reg) < 0) {
|
||||
printk(KERN_ERR "Failed to initialize rtlib!\n");
|
||||
goto out_return;
|
||||
}
|
||||
|
||||
if (!(master = ecrt_request_master(0))) {
|
||||
printk(KERN_ERR "Failed to request master 0!\n");
|
||||
goto out_msr_cleanup;
|
||||
}
|
||||
|
||||
ecrt_master_callbacks(master, request_lock, release_lock, NULL);
|
||||
|
||||
printk(KERN_INFO "Creating domains...\n");
|
||||
if (!(domain1 = ecrt_master_create_domain(master))) {
|
||||
printk(KERN_ERR "Failed to create domains!\n");
|
||||
goto out_release_master;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "Registering Pdos...\n");
|
||||
if (ecrt_domain_register_pdo_list(domain1, domain1_pdos)) {
|
||||
printk(KERN_ERR "Failed to register Pdos.\n");
|
||||
goto out_release_master;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "Activating master...\n");
|
||||
if (ecrt_master_activate(master)) {
|
||||
printk(KERN_ERR "Could not activate master!\n");
|
||||
goto out_release_master;
|
||||
}
|
||||
|
||||
printk("Starting cyclic sample thread...\n");
|
||||
ticks = start_rt_timer(nano2count(TIMERTICKS));
|
||||
if (rt_task_init(&task, msr_run, 0, 2000, 0, 1, NULL)) {
|
||||
printk(KERN_ERR "Failed to init RTAI task!\n");
|
||||
goto out_stop_timer;
|
||||
}
|
||||
if (rt_task_make_periodic(&task, rt_get_time() + ticks, ticks)) {
|
||||
printk(KERN_ERR "Failed to run RTAI task!\n");
|
||||
goto out_stop_task;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "=== EtherCAT RTAI MSR sample module started. ===\n");
|
||||
return 0;
|
||||
|
||||
out_stop_task:
|
||||
rt_task_delete(&task);
|
||||
out_stop_timer:
|
||||
stop_rt_timer();
|
||||
out_release_master:
|
||||
ecrt_release_master(master);
|
||||
out_msr_cleanup:
|
||||
msr_rtlib_cleanup();
|
||||
out_return:
|
||||
rt_sem_delete(&master_sem);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void __exit cleanup_mod(void)
|
||||
{
|
||||
printk(KERN_INFO "=== Unloading EtherCAT RTAI MSR sample module... ===\n");
|
||||
|
||||
rt_task_delete(&task);
|
||||
stop_rt_timer();
|
||||
ecrt_release_master(master);
|
||||
rt_sem_delete(&master_sem);
|
||||
msr_rtlib_cleanup();
|
||||
|
||||
printk(KERN_INFO "=== EtherCAT RTAI MSR sample module unloaded. ===\n");
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Florian Pose <fp@igh-essen.com>");
|
||||
MODULE_DESCRIPTION("EtherCAT RTAI MSR sample module");
|
||||
|
||||
module_init(init_mod);
|
||||
module_exit(cleanup_mod);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -1,267 +0,0 @@
|
|||
#!/usr/bin/perl -w
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2006 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
|
||||
# as published by the Free Software Foundation; either version 2 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# 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 right to use EtherCAT Technology is granted and comes free of
|
||||
# charge under condition of compatibility of product made by
|
||||
# Licensee. People intending to distribute/sell products based on the
|
||||
# code, have to sign an agreement to guarantee that products using
|
||||
# software based on IgH EtherCAT master stay compatible with the actual
|
||||
# EtherCAT specification (which are released themselves as an open
|
||||
# standard) as the (only) precondition to have the right to use EtherCAT
|
||||
# Technology, IP and trade marks.
|
||||
#
|
||||
#------------------------------------------------------------------------------
|
||||
#
|
||||
# Multithreaded Server
|
||||
# according to the example from "Programming Perl"
|
||||
# this code is improved according to the example from
|
||||
# perldoc perlipc, so now safely being usable under Perl 5.8
|
||||
# (see note (*))
|
||||
#
|
||||
# works with read/write on a device-file
|
||||
#
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
require 5.002;
|
||||
use strict;
|
||||
BEGIN { $ENV{PATH} = '/opt/msr/bin:/usr/bin:/bin' }
|
||||
use Socket;
|
||||
use Carp;
|
||||
use FileHandle;
|
||||
use Getopt::Std;
|
||||
|
||||
use Sys::Syslog qw(:DEFAULT setlogsock);
|
||||
|
||||
use vars qw (
|
||||
$self $pid $dolog $port $dev %opts $selfbase
|
||||
$len $offset $stream $written $read $log $blksize
|
||||
$instdir
|
||||
$authfile %authhosts
|
||||
);
|
||||
|
||||
|
||||
# Do logging to local syslogd by unix-domain socket instead of inetd
|
||||
setlogsock("unix");
|
||||
|
||||
# Prototypes and some little Tools
|
||||
sub spawn;
|
||||
sub logmsg {
|
||||
my ($level, $debug, @text) = @_;
|
||||
syslog("daemon|$level", @text) if $debug > $dolog;
|
||||
# print STDERR "daemon|$level", @text, "\n" if $dolog;
|
||||
}
|
||||
sub out {
|
||||
my $waitpid = wait;
|
||||
logmsg("notice", 2, "$waitpid exited");
|
||||
unlink "$selfbase.pid";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
sub help {
|
||||
print "\n usage: $0 [-l og] [-h elp] [-p port] [-d device]\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
# Process Options
|
||||
%opts = (
|
||||
"l" => 1,
|
||||
"h" => 0,
|
||||
"p" => 2345,
|
||||
"d" => "/dev/msr"
|
||||
);
|
||||
|
||||
getopts("lhp:d:", \%opts);
|
||||
|
||||
help if $opts{"h"};
|
||||
|
||||
( $self = $0 ) =~ s+.*/++ ;
|
||||
( $selfbase = $self ) =~ s/\..*//;
|
||||
$log = "$selfbase.log";
|
||||
$dolog = $opts{"l"};
|
||||
$port = $opts{"p"};
|
||||
$dev = $opts{"d"};
|
||||
$blksize = 1024; # try to write as much bytes
|
||||
$instdir = "/opt/msr";
|
||||
$authfile = "$instdir/etc/hosts.auth";
|
||||
|
||||
# Start logging
|
||||
openlog($self, 'pid');
|
||||
|
||||
# Flush Output, dont buffer
|
||||
$| = 1;
|
||||
|
||||
# first fork and run in background
|
||||
if ($pid = fork) {
|
||||
# open LOG, ">$log" if $dolog;
|
||||
# close LOG;
|
||||
logmsg("notice", 2, "forked process: $pid\n");
|
||||
exit 0;
|
||||
}
|
||||
|
||||
# Server tells about startup success
|
||||
open (PID, ">/$instdir/var/run/$selfbase.pid");
|
||||
print PID "$$\n";
|
||||
close PID;
|
||||
|
||||
# Cleanup on exit (due to kill -TERM signal)
|
||||
$SIG{TERM} = \&out;
|
||||
|
||||
# We use streams
|
||||
my $proto = getprotobyname('tcp');
|
||||
|
||||
# Open Server socket
|
||||
socket(Server, PF_INET, SOCK_STREAM, $proto) or die "socket: $!";
|
||||
setsockopt(Server, SOL_SOCKET, SO_REUSEADDR, pack("l", 1))
|
||||
or die "setsocketopt: $!";
|
||||
bind (Server, sockaddr_in($port, INADDR_ANY))
|
||||
or die "bind: $!";
|
||||
listen (Server, SOMAXCONN)
|
||||
or die "listen: $!";
|
||||
|
||||
%authhosts = ();
|
||||
# get authorized hosts
|
||||
open (AUTH, $authfile)
|
||||
or logmsg ("notice", 2, "Could not read allowed hosts file: $authfile");
|
||||
while (<AUTH>) {
|
||||
chomp;
|
||||
my $host = lc $_;
|
||||
if ($host =~ /^[\d\w]/) {
|
||||
$authhosts{$_} = 1;
|
||||
logmsg ("notice", 2, "Authorized host: >$host<");
|
||||
}
|
||||
}
|
||||
close (AUTH);
|
||||
|
||||
# tell about open server socket
|
||||
logmsg ("notice", 2, "Server started at port $port");
|
||||
|
||||
my $waitedpid = 0;
|
||||
my $paddr;
|
||||
|
||||
# wait for children to return, thus avoiding zombies
|
||||
# improvement (*)
|
||||
use POSIX ":sys_wait_h";
|
||||
sub REAPER {
|
||||
my $child;
|
||||
while (($waitedpid = waitpid(-1,WNOHANG)) > 0) {
|
||||
logmsg ("notice", 2, "reaped $waitedpid", ($? ? " with exit $?" : ""));
|
||||
}
|
||||
$SIG{CHLD} = \&REAPER; # loathe sysV
|
||||
}
|
||||
|
||||
# also all sub-processes should wait for their children
|
||||
$SIG{CHLD} = \&REAPER;
|
||||
|
||||
# start a new server for every incoming request
|
||||
# improvement (*) -- loop forever
|
||||
|
||||
while ( 1 ) {
|
||||
for ( $waitedpid = 0;
|
||||
($paddr = accept(Client,Server)) || $waitedpid;
|
||||
$waitedpid = 0, close Client ) {
|
||||
next if $waitedpid and not $paddr;
|
||||
my ($port, $iaddr) = sockaddr_in($paddr);
|
||||
my $name = lc gethostbyaddr($iaddr, AF_INET);
|
||||
my $ipaddr = inet_ntoa($iaddr);
|
||||
my $n = 0;
|
||||
|
||||
# tell about the requesting client
|
||||
logmsg ("info", 2, "Connection from >$ipaddr< ($name) at port $port");
|
||||
|
||||
spawn sub {
|
||||
my ($head, $hlen, $pos, $pegel, $typ, $siz, $nch, $nrec, $dat, $i, $j, $n, $llen);
|
||||
my ($watchpegel, $shmpegel);
|
||||
my ($rin, $rout, $in, $line, $data_requested, $oversample);
|
||||
my (@channels);
|
||||
|
||||
# to use stdio on writing to Client
|
||||
Client->autoflush();
|
||||
|
||||
# Open Device
|
||||
sysopen (DEV, "$dev", O_RDWR | O_NONBLOCK, 0666) or die("can't open $dev");
|
||||
|
||||
# Bitmask to check for input on stdin
|
||||
$rin = "";
|
||||
vec($rin, fileno(Client), 1) = 1;
|
||||
|
||||
# check for authorized hosts
|
||||
my $access = 'deny';
|
||||
$access = 'allow' if $authhosts{$ipaddr};
|
||||
$line = "<remote_host host=\"$ipaddr\" access=\"$access\">\n";
|
||||
logmsg ("info", 2, $line);
|
||||
$len = length $line;
|
||||
$offset = 0;
|
||||
while ($len) {
|
||||
$written = syswrite (DEV, $line, $len, $offset);
|
||||
$len -= $written;
|
||||
$offset += $written;
|
||||
}
|
||||
|
||||
while ( 1 ) {
|
||||
$in = select ($rout=$rin, undef, undef, 0.0); # poll client
|
||||
# look for any Input from Client
|
||||
if ($in) {
|
||||
# exit on EOF
|
||||
$len = sysread (Client, $line, $blksize) or exit;
|
||||
logmsg("info", 0, "got $len bytes: \"$line\"");
|
||||
$offset = 0;
|
||||
# copy request to device
|
||||
while ($len) {
|
||||
$written = syswrite (DEV, $line, $len, $offset);
|
||||
$len -= $written;
|
||||
$offset += $written;
|
||||
}
|
||||
}
|
||||
# look for some output from device
|
||||
if ($len = sysread DEV, $stream, $blksize) {
|
||||
print Client $stream;
|
||||
} else {
|
||||
select undef, undef, undef, 0.1; # calm down if nothing on device
|
||||
}
|
||||
}
|
||||
};
|
||||
logmsg("info", 2, "spawned\n");
|
||||
}
|
||||
logmsg("info", 2, "server loop\n");
|
||||
}
|
||||
|
||||
sub spawn {
|
||||
my $coderef = shift;
|
||||
|
||||
unless (@_ == 0 && $coderef && ref($coderef) eq 'CODE') {
|
||||
confess "usage: spawn CODEREF";
|
||||
}
|
||||
my $pid;
|
||||
if (!defined($pid = fork)) {
|
||||
logmsg ("notice", 2, "fork failed: $!");
|
||||
return;
|
||||
} elsif ($pid) {
|
||||
logmsg ("notice", 2, "Request $pid");
|
||||
return; # Parent
|
||||
}
|
||||
|
||||
# do not use fdup as in the original example
|
||||
# open (STDIN, "<&Client") or die "Can't dup client to stdin";
|
||||
# open (STDOUT, ">&Client") or die "Can't dup client to stdout";
|
||||
# STDOUT->autoflush();
|
||||
exit &$coderef();
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
-------------------------------------------------------------------------------
|
||||
|
||||
$Id$
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
This is a minimal example module for the use of the EtherCAT master realtime
|
||||
interface with an RTAI thread.
|
||||
|
||||
The module expects an RTAI installation. Configure the master sources
|
||||
specifying --with-rtai-dir to have the right include paths.
|
||||
|
||||
Most probably you'll have different EtherCAT slaves present. Try adjusting the
|
||||
section "process data" in rtai_sample.c to your bus configuration.
|
||||
|
||||
There are some features that can be disabled by commenting out the respective
|
||||
defines at the head of rtai_sample.c.
|
||||
|
||||
---
|
||||
|
||||
To build the example module, call:
|
||||
|
||||
make modules
|
||||
|
||||
To run it, load the appropriate RTAI modules and call:
|
||||
|
||||
insmod ec_rtai_sample.ko
|
||||
|
||||
...and watch the system logs for the outputs.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
|
@ -37,100 +37,210 @@
|
|||
#include <linux/module.h>
|
||||
|
||||
// RTAI
|
||||
#include "rtai_sched.h"
|
||||
#include "rtai_sem.h"
|
||||
#include <rtai_sched.h>
|
||||
#include <rtai_sem.h>
|
||||
|
||||
// EtherCAT
|
||||
#include "../../include/ecrt.h"
|
||||
#include "../../include/ecdb.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
// RTAI task frequency in Hz
|
||||
#define FREQUENCY 2000
|
||||
// Module parameters
|
||||
|
||||
#define FREQUENCY 2000 // task frequency in Hz
|
||||
#define INHIBIT_TIME 20
|
||||
|
||||
#define TIMERTICKS (1000000000 / FREQUENCY)
|
||||
|
||||
// Optional features (comment to disable)
|
||||
#define CONFIGURE_PDOS
|
||||
|
||||
#define PFX "ec_rtai_sample: "
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
// EtherCAT
|
||||
static ec_master_t *master = NULL;
|
||||
static ec_master_state_t master_state = {};
|
||||
spinlock_t master_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
static ec_domain_t *domain1 = NULL;
|
||||
static ec_domain_state_t domain1_state = {};
|
||||
|
||||
static ec_slave_config_t *sc_ana_in = NULL;
|
||||
static ec_slave_config_state_t sc_ana_in_state = {};
|
||||
|
||||
// RTAI
|
||||
static RT_TASK task;
|
||||
static SEM master_sem;
|
||||
static cycles_t t_last_cycle = 0, t_critical;
|
||||
|
||||
// EtherCAT
|
||||
static ec_master_t *master = NULL;
|
||||
static ec_domain_t *domain1 = NULL;
|
||||
static ec_master_status_t master_status, old_status = {};
|
||||
/*****************************************************************************/
|
||||
|
||||
// data fields
|
||||
static void *r_dig_out;
|
||||
static void *r_ana_out;
|
||||
static void *r_count;
|
||||
//static void *r_freq;
|
||||
// process data
|
||||
static uint8_t *domain1_pd; // process data memory
|
||||
|
||||
const static ec_pdo_reg_t domain1_pdo_regs[] = {
|
||||
{"2", Beckhoff_EL2004_Outputs, &r_dig_out},
|
||||
{"3", Beckhoff_EL4132_Output1, &r_ana_out},
|
||||
{"#888:1", Beckhoff_EL5101_Value, &r_count},
|
||||
//{"4", Beckhoff_EL5101_Frequency, &r_freq},
|
||||
#define AnaInSlavePos 0, 1
|
||||
#define DigOutSlavePos 0, 3
|
||||
|
||||
#define Beckhoff_EL2004 0x00000002, 0x07D43052
|
||||
#define Beckhoff_EL3162 0x00000002, 0x0C5A3052
|
||||
|
||||
static unsigned int off_ana_in; // offsets for Pdo entries
|
||||
static unsigned int off_dig_out;
|
||||
|
||||
const static ec_pdo_entry_reg_t domain1_regs[] = {
|
||||
{AnaInSlavePos, Beckhoff_EL3162, 0x3101, 2, &off_ana_in},
|
||||
{DigOutSlavePos, Beckhoff_EL2004, 0x3001, 1, &off_dig_out},
|
||||
{}
|
||||
};
|
||||
|
||||
static unsigned int counter = 0;
|
||||
static unsigned int blink = 0;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifdef CONFIGURE_PDOS
|
||||
static ec_pdo_entry_info_t el3162_channel1[] = {
|
||||
{0x3101, 1, 8}, // status
|
||||
{0x3101, 2, 16} // value
|
||||
};
|
||||
|
||||
static ec_pdo_entry_info_t el3162_channel2[] = {
|
||||
{0x3102, 1, 8}, // status
|
||||
{0x3102, 2, 16} // value
|
||||
};
|
||||
|
||||
static ec_pdo_info_t el3162_pdos[] = {
|
||||
{0x1A00, 2, el3162_channel1},
|
||||
{0x1A01, 2, el3162_channel2}
|
||||
};
|
||||
|
||||
static ec_sync_info_t el3162_syncs[] = {
|
||||
{2, EC_DIR_OUTPUT},
|
||||
{3, EC_DIR_INPUT, 2, el3162_pdos},
|
||||
{0xff}
|
||||
};
|
||||
|
||||
static ec_pdo_entry_info_t el2004_channels[] = {
|
||||
{0x3001, 1, 1}, // Value 1
|
||||
{0x3001, 2, 1}, // Value 2
|
||||
{0x3001, 3, 1}, // Value 3
|
||||
{0x3001, 4, 1} // Value 4
|
||||
};
|
||||
|
||||
static ec_pdo_info_t el2004_pdos[] = {
|
||||
{0x1600, 1, &el2004_channels[0]},
|
||||
{0x1601, 1, &el2004_channels[1]},
|
||||
{0x1602, 1, &el2004_channels[2]},
|
||||
{0x1603, 1, &el2004_channels[3]}
|
||||
};
|
||||
|
||||
static ec_sync_info_t el2004_syncs[] = {
|
||||
{0, EC_DIR_OUTPUT, 4, el2004_pdos},
|
||||
{1, EC_DIR_INPUT},
|
||||
{0xff}
|
||||
};
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void check_domain1_state(void)
|
||||
{
|
||||
ec_domain_state_t ds;
|
||||
|
||||
spin_lock(&master_lock);
|
||||
ecrt_domain_state(domain1, &ds);
|
||||
spin_unlock(&master_lock);
|
||||
|
||||
if (ds.working_counter != domain1_state.working_counter)
|
||||
printk(KERN_INFO PFX "Domain1: WC %u.\n", ds.working_counter);
|
||||
if (ds.wc_state != domain1_state.wc_state)
|
||||
printk(KERN_INFO PFX "Domain1: State %u.\n", ds.wc_state);
|
||||
|
||||
domain1_state = ds;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void check_master_state(void)
|
||||
{
|
||||
ec_master_state_t ms;
|
||||
|
||||
spin_lock(&master_lock);
|
||||
ecrt_master_state(master, &ms);
|
||||
spin_unlock(&master_lock);
|
||||
|
||||
if (ms.slaves_responding != master_state.slaves_responding)
|
||||
printk(KERN_INFO PFX "%u slave(s).\n", ms.slaves_responding);
|
||||
if (ms.al_states != master_state.al_states)
|
||||
printk(KERN_INFO PFX "AL states: 0x%02X.\n", ms.al_states);
|
||||
if (ms.link_up != master_state.link_up)
|
||||
printk(KERN_INFO PFX "Link is %s.\n", ms.link_up ? "up" : "down");
|
||||
|
||||
master_state = ms;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void check_slave_config_states(void)
|
||||
{
|
||||
ec_slave_config_state_t s;
|
||||
|
||||
spin_lock(&master_lock);
|
||||
ecrt_slave_config_state(sc_ana_in, &s);
|
||||
spin_unlock(&master_lock);
|
||||
|
||||
if (s.al_state != sc_ana_in_state.al_state)
|
||||
printk(KERN_INFO PFX "AnaIn: State 0x%02X.\n", s.al_state);
|
||||
if (s.online != sc_ana_in_state.online)
|
||||
printk(KERN_INFO PFX "AnaIn: %s.\n", s.online ? "online" : "offline");
|
||||
if (s.operational != sc_ana_in_state.operational)
|
||||
printk(KERN_INFO PFX "AnaIn: %soperational.\n",
|
||||
s.operational ? "" : "Not ");
|
||||
|
||||
sc_ana_in_state = s;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void run(long data)
|
||||
{
|
||||
static unsigned int blink = 0;
|
||||
static unsigned int counter = 0;
|
||||
|
||||
while (1) {
|
||||
t_last_cycle = get_cycles();
|
||||
|
||||
// receive process data
|
||||
rt_sem_wait(&master_sem);
|
||||
ecrt_master_receive(master);
|
||||
ecrt_domain_process(domain1);
|
||||
rt_sem_signal(&master_sem);
|
||||
|
||||
// process data
|
||||
EC_WRITE_U8(r_dig_out, blink ? 0x0F : 0x00);
|
||||
// check process data state (optional)
|
||||
check_domain1_state();
|
||||
|
||||
if (counter) {
|
||||
counter--;
|
||||
} else { // do this at 1 Hz
|
||||
counter = FREQUENCY;
|
||||
|
||||
// calculate new process data
|
||||
blink = !blink;
|
||||
|
||||
// check for master state (optional)
|
||||
check_master_state();
|
||||
|
||||
// check for islave configuration state(s) (optional)
|
||||
check_slave_config_states();
|
||||
}
|
||||
|
||||
// write process data
|
||||
EC_WRITE_U8(domain1_pd + off_dig_out, blink ? 0x06 : 0x09);
|
||||
|
||||
rt_sem_wait(&master_sem);
|
||||
ecrt_domain_queue(domain1);
|
||||
ecrt_master_send(master);
|
||||
rt_sem_signal(&master_sem);
|
||||
|
||||
if (counter) {
|
||||
counter--;
|
||||
}
|
||||
else {
|
||||
counter = FREQUENCY;
|
||||
blink = !blink;
|
||||
|
||||
rt_sem_wait(&master_sem);
|
||||
ecrt_master_get_status(master, &master_status);
|
||||
rt_sem_signal(&master_sem);
|
||||
|
||||
if (master_status.bus_status != old_status.bus_status) {
|
||||
printk(KERN_INFO PFX "bus status changed to %i.\n",
|
||||
master_status.bus_status);
|
||||
}
|
||||
if (master_status.bus_tainted != old_status.bus_tainted) {
|
||||
printk(KERN_INFO PFX "tainted flag changed to %u.\n",
|
||||
master_status.bus_tainted);
|
||||
}
|
||||
if (master_status.slaves_responding !=
|
||||
old_status.slaves_responding) {
|
||||
printk(KERN_INFO PFX "slaves_responding changed to %u.\n",
|
||||
master_status.slaves_responding);
|
||||
}
|
||||
|
||||
old_status = master_status;
|
||||
}
|
||||
|
||||
rt_task_wait_period();
|
||||
}
|
||||
}
|
||||
|
|
@ -159,6 +269,9 @@ void release_lock(void *data)
|
|||
int __init init_mod(void)
|
||||
{
|
||||
RTIME tick_period, requested_ticks, now;
|
||||
#ifdef CONFIGURE_PDOS
|
||||
ec_slave_config_t *sc;
|
||||
#endif
|
||||
|
||||
printk(KERN_INFO PFX "Starting...\n");
|
||||
|
||||
|
|
@ -173,15 +286,39 @@ int __init init_mod(void)
|
|||
|
||||
ecrt_master_callbacks(master, request_lock, release_lock, NULL);
|
||||
|
||||
printk(KERN_INFO PFX "Creating domain...\n");
|
||||
printk(KERN_INFO PFX "Registering domain...\n");
|
||||
if (!(domain1 = ecrt_master_create_domain(master))) {
|
||||
printk(KERN_ERR PFX "Domain creation failed!\n");
|
||||
goto out_release_master;
|
||||
}
|
||||
|
||||
printk(KERN_INFO PFX "Registering Pdos...\n");
|
||||
if (ecrt_domain_register_pdo_list(domain1, domain1_pdo_regs)) {
|
||||
printk(KERN_ERR PFX "Pdo registration failed!\n");
|
||||
if (!(sc_ana_in = ecrt_master_slave_config(
|
||||
master, AnaInSlavePos, Beckhoff_EL3162))) {
|
||||
printk(KERN_ERR PFX "Failed to get slave configuration.\n");
|
||||
goto out_release_master;
|
||||
}
|
||||
|
||||
#ifdef CONFIGURE_PDOS
|
||||
printk(KERN_INFO PFX "Configuring Pdos...\n");
|
||||
if (ecrt_slave_config_sync_managers(sc_ana_in, EC_END, el3162_syncs)) {
|
||||
printk(KERN_ERR PFX "Failed to configure Pdos.\n");
|
||||
goto out_release_master;
|
||||
}
|
||||
|
||||
if (!(sc = ecrt_master_slave_config(master, DigOutSlavePos, Beckhoff_EL2004))) {
|
||||
printk(KERN_ERR PFX "Failed to get slave configuration.\n");
|
||||
goto out_release_master;
|
||||
}
|
||||
|
||||
if (ecrt_slave_config_sync_managers(sc, EC_END, el2004_syncs)) {
|
||||
printk(KERN_ERR PFX "Failed to configure Pdos.\n");
|
||||
goto out_release_master;
|
||||
}
|
||||
#endif
|
||||
|
||||
printk(KERN_INFO PFX "Registering Pdo entries...\n");
|
||||
if (ecrt_domain_reg_pdo_entry_list(domain1, domain1_regs)) {
|
||||
printk(KERN_ERR PFX "Pdo entry registration failed!\n");
|
||||
goto out_release_master;
|
||||
}
|
||||
|
||||
|
|
@ -191,6 +328,9 @@ int __init init_mod(void)
|
|||
goto out_release_master;
|
||||
}
|
||||
|
||||
// Get internal process data for domain
|
||||
domain1_pd = ecrt_domain_data(domain1);
|
||||
|
||||
printk(KERN_INFO PFX "Starting cyclic sample thread...\n");
|
||||
requested_ticks = nano2count(TIMERTICKS);
|
||||
tick_period = start_rt_timer(requested_ticks);
|
||||
|
|
|
|||
Loading…
Reference in New Issue